From d8440e1fdc84baee8e781333da6a26b53f45119b Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 20 May 2014 09:02:22 +0200 Subject: [PATCH 001/151] 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/151] 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 3a7e2f8bb579e79c72d12d4e84711f4bf8a3f04f Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 21 May 2014 14:18:14 +0200 Subject: [PATCH 003/151] Allow invoking Journal instruction with non-existing index This is used by the MG_EscortScholar1 quest. --- apps/openmw/mwscript/dialogueextensions.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwscript/dialogueextensions.cpp b/apps/openmw/mwscript/dialogueextensions.cpp index a882ae05e7..6958084f4a 100644 --- a/apps/openmw/mwscript/dialogueextensions.cpp +++ b/apps/openmw/mwscript/dialogueextensions.cpp @@ -34,7 +34,15 @@ namespace MWScript Interpreter::Type_Integer index = runtime[0].mInteger; runtime.pop(); - MWBase::Environment::get().getJournal()->addEntry (quest, index); + // Invoking Journal with a non-existing index is allowed, and triggers no errors. Seriously? :( + try + { + MWBase::Environment::get().getJournal()->addEntry (quest, index); + } + catch (...) + { + MWBase::Environment::get().getJournal()->setJournalIndex(quest, index); + } } }; From f812746010a835b0b8dba4a4d333fafa9c363170 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 21 May 2014 16:36:55 +0200 Subject: [PATCH 004/151] Auto-select first save in load dialog --- apps/openmw/mwgui/savegamedialog.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 16e939eb24..6048e49b41 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -256,7 +256,16 @@ namespace MWGui { mSaveList->addItem(it->mProfile.mDescription); } - onSlotSelected(mSaveList, MyGUI::ITEM_NONE); + // When loading, Auto-select the first save, if there is one + if (mSaveList->getItemCount() && !mSaving) + { + mSaveList->setIndexSelected(0); + onSlotSelected(mSaveList, 0); + // Give key focus to save list so we can confirm the selection with Enter + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mSaveList); + } + else + onSlotSelected(mSaveList, MyGUI::ITEM_NONE); } void SaveGameDialog::onSlotSelected(MyGUI::ListBox *sender, size_t pos) From cf07d2ab93fcb05e6e7c5e92552c6da083026e29 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 21 May 2014 16:38:50 +0200 Subject: [PATCH 005/151] Fix swapped position of Save and Load menu buttons --- apps/openmw/mwgui/mainmenu.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index 8b44af2ef3..bafd04311b 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -165,15 +165,15 @@ namespace MWGui buttons.push_back("newgame"); - if (MWBase::Environment::get().getStateManager()->characterBegin()!= - MWBase::Environment::get().getStateManager()->characterEnd()) - buttons.push_back("loadgame"); - if (state==MWBase::StateManager::State_Running && MWBase::Environment::get().getWorld()->getGlobalInt ("chargenstate")==-1 && MWBase::Environment::get().getWindowManager()->isSavingAllowed()) buttons.push_back("savegame"); + if (MWBase::Environment::get().getStateManager()->characterBegin()!= + MWBase::Environment::get().getStateManager()->characterEnd()) + buttons.push_back("loadgame"); + buttons.push_back("options"); if (state==MWBase::StateManager::State_NoGame) From 18bba6bcece30f3b0aaa8224b810fbc882237dbf Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 22 May 2014 11:03:45 +0200 Subject: [PATCH 006/151] Fix layout glitch when autosaving --- apps/openmw/mwgui/waitdialog.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index ed1b9e0a90..d5b52ebae8 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -118,11 +118,12 @@ namespace MWGui void WaitDialog::startWaiting(int hoursToWait) { + if(Settings::Manager::getBool("autosave","Saves") && mSleeping) //autosaves when enabled and sleeping + MWBase::Environment::get().getStateManager()->quickSave("Autosave"); + MWBase::World* world = MWBase::Environment::get().getWorld(); world->getFader ()->fadeOut(0.2); setVisible(false); - if(Settings::Manager::getBool("autosave","Saves") && mSleeping) //autosaves when enabled and sleeping (Not resting, apparently) - MWBase::Environment::get().getStateManager()->quickSave("Autosave"); mProgressBar.setVisible (true); mWaiting = true; From c6c254d279259a105fe4acee9f86a794af700750 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 22 May 2014 11:08:36 +0200 Subject: [PATCH 007/151] Do not trigger levelup if rest was interrupted --- apps/openmw/mwgui/waitdialog.cpp | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index d5b52ebae8..7eaba93613 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -219,8 +219,20 @@ namespace MWGui } if (mCurHour > mHours) + { stopWaiting(); + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + const MWMechanics::NpcStats &pcstats = MWWorld::Class::get(player).getNpcStats(player); + + // trigger levelup if possible + const MWWorld::Store &gmst = + MWBase::Environment::get().getWorld()->getStore().get(); + if (mSleeping && pcstats.getLevelProgress () >= gmst.find("iLevelUpTotal")->getInt()) + { + MWBase::Environment::get().getWindowManager()->pushGuiMode (GM_Levelup); + } + } } void WaitDialog::stopWaiting () @@ -230,17 +242,6 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Rest); MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_RestBed); mWaiting = false; - - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); - const MWMechanics::NpcStats &pcstats = MWWorld::Class::get(player).getNpcStats(player); - - // trigger levelup if possible - const MWWorld::Store &gmst = - MWBase::Environment::get().getWorld()->getStore().get(); - if (mSleeping && pcstats.getLevelProgress () >= gmst.find("iLevelUpTotal")->getInt()) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode (GM_Levelup); - } } From 3380e1e1c563850d9b63a23f4b2c15c098232191 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 22 May 2014 12:14:33 +0200 Subject: [PATCH 008/151] Fix ShouldAttack filter This makes NPCs exit dialogue properly when they should attack as a result of taunting actions. --- apps/openmw/mwdialogue/filter.cpp | 2 +- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index 8b9ee9184f..5bdf80593b 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -539,7 +539,7 @@ bool MWDialogue::Filter::getSelectStructBoolean (const SelectWrapper& select) co case SelectWrapper::Function_ShouldAttack: - return MWWorld::Class::get (mActor).getCreatureStats (mActor).isHostile(); + return mActor.getClass().getCreatureStats(mActor).getAiSetting(MWMechanics::CreatureStats::AI_Fight).getModified() >= 80; case SelectWrapper::Function_CreatureTargetted: diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index bf9a11d6e5..f5f2443303 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -666,8 +666,6 @@ namespace MWMechanics int fight = npcStats.getAiSetting(MWMechanics::CreatureStats::AI_Fight).getBase(); npcStats.setAiSetting (MWMechanics::CreatureStats::AI_Flee, std::max(0, std::min(100, flee + int(std::max(iPerMinChange, s))))); - // TODO: initiate combat and quit dialogue if fight rating is too high - // or should setAiSetting handle this? npcStats.setAiSetting (MWMechanics::CreatureStats::AI_Fight, std::max(0, std::min(100, fight + int(std::min(-iPerMinChange, -s))))); } From 4b5f02f6447a6596640c155c5eaaab7318d43d20 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 22 May 2014 15:29:36 +0200 Subject: [PATCH 009/151] Remove useless throwing of exception --- apps/openmw/mwmechanics/levelledlist.hpp | 38 +++++++++++------------- apps/openmw/mwworld/esmstore.hpp | 3 +- 2 files changed, 20 insertions(+), 21 deletions(-) diff --git a/apps/openmw/mwmechanics/levelledlist.hpp b/apps/openmw/mwmechanics/levelledlist.hpp index 6888d88a68..5d9e291181 100644 --- a/apps/openmw/mwmechanics/levelledlist.hpp +++ b/apps/openmw/mwmechanics/levelledlist.hpp @@ -53,29 +53,27 @@ namespace MWMechanics return std::string(); std::string item = candidates[std::rand()%candidates.size()]; - // Is this another levelled item or a real item? - try + // Vanilla doesn't fail on nonexistent items in levelled lists + if (!MWBase::Environment::get().getWorld()->getStore().find(Misc::StringUtils::lowerCase(item))) { - MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), item, 1); - if (ref.getPtr().getTypeName() != typeid(ESM::ItemLevList).name() - && ref.getPtr().getTypeName() != typeid(ESM::CreatureLevList).name()) - { - return item; - } - else - { - if (ref.getPtr().getTypeName() == typeid(ESM::ItemLevList).name()) - return getLevelledItem(ref.getPtr().get()->mBase, failChance); - else - return getLevelledItem(ref.getPtr().get()->mBase, failChance); - } - } - catch (std::logic_error&) - { - // Vanilla doesn't fail on nonexistent items in levelled lists - std::cerr << "Warning: ignoring nonexistent item '" << item << "'" << std::endl; + std::cerr << "Warning: ignoring nonexistent item '" << item << "' in levelled list '" << levItem->mId << "'" << std::endl; return std::string(); } + + // Is this another levelled item or a real item? + MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), item, 1); + if (ref.getPtr().getTypeName() != typeid(ESM::ItemLevList).name() + && ref.getPtr().getTypeName() != typeid(ESM::CreatureLevList).name()) + { + return item; + } + else + { + if (ref.getPtr().getTypeName() == typeid(ESM::ItemLevList).name()) + return getLevelledItem(ref.getPtr().get()->mBase, failChance); + else + return getLevelledItem(ref.getPtr().get()->mBase, failChance); + } } } diff --git a/apps/openmw/mwworld/esmstore.hpp b/apps/openmw/mwworld/esmstore.hpp index c6c9c1ffe2..90786acd42 100644 --- a/apps/openmw/mwworld/esmstore.hpp +++ b/apps/openmw/mwworld/esmstore.hpp @@ -85,7 +85,8 @@ namespace MWWorld return mStores.end(); } - // Look up the given ID in 'all'. Returns 0 if not found. + /// Look up the given ID in 'all'. Returns 0 if not found. + /// \note id must be in lower case. int find(const std::string &id) const { std::map::const_iterator it = mIds.find(id); From cba50c733839390736fa648f777dcddfcc99a90c Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 22 May 2014 15:46:35 +0200 Subject: [PATCH 010/151] Optimize ManualRef: look up correct Store instead of searching --- apps/openmw/mwworld/manualref.hpp | 75 ++++++++++++++++--------------- 1 file changed, 39 insertions(+), 36 deletions(-) diff --git a/apps/openmw/mwworld/manualref.hpp b/apps/openmw/mwworld/manualref.hpp index 0e21c55acd..99accbb979 100644 --- a/apps/openmw/mwworld/manualref.hpp +++ b/apps/openmw/mwworld/manualref.hpp @@ -19,54 +19,57 @@ namespace MWWorld ManualRef& operator= (const ManualRef&); template - bool create (const MWWorld::Store& list, const std::string& name) + void create (const MWWorld::Store& list, const std::string& name) { - if (const T *instance = list.search (name)) - { - LiveCellRef ref; - ref.mBase = instance; - ref.mRef.mRefNum.mIndex = 0; - ref.mRef.mRefNum.mContentFile = -1; + const T* base = list.find(name); - mRef = ref; - mPtr = Ptr (&boost::any_cast&> (mRef), 0); + LiveCellRef ref; + ref.mBase = base; + ref.mRef.mRefNum.mIndex = 0; + ref.mRef.mRefNum.mContentFile = -1; - return true; - } - - return false; + mRef = ref; + mPtr = Ptr (&boost::any_cast&> (mRef), 0); } public: ManualRef (const MWWorld::ESMStore& store, const std::string& name, const int count=1) { - // create - if (!create (store.get(), name) && - !create (store.get(), name) && - !create (store.get(), name) && - !create (store.get(), name) && - !create (store.get(), name) && - !create (store.get(), name) && - !create (store.get(), name) && - !create (store.get(), name) && - !create (store.get(), name) && - !create (store.get(), name) && - !create (store.get(), name) && - !create (store.get(), name) && - !create (store.get(), name) && - !create (store.get(), name) && - !create (store.get(), name) && - !create (store.get(), name) && - !create (store.get(), name) && - !create (store.get(), name) && - !create (store.get(), name) && - !create (store.get(), name)) - throw std::logic_error ("failed to create manual cell ref for " + name); + std::string lowerName = Misc::StringUtils::lowerCase (name); + switch (store.find (lowerName)) + { + case ESM::REC_ACTI: create (store.get(), lowerName); break; + case ESM::REC_ALCH: create (store.get(), lowerName); break; + case ESM::REC_APPA: create (store.get(), lowerName); break; + case ESM::REC_ARMO: create (store.get(), lowerName); break; + case ESM::REC_BOOK: create (store.get(), lowerName); break; + case ESM::REC_CLOT: create (store.get(), lowerName); break; + case ESM::REC_CONT: create (store.get(), lowerName); break; + case ESM::REC_CREA: create (store.get(), lowerName); break; + case ESM::REC_DOOR: create (store.get(), lowerName); break; + case ESM::REC_INGR: create (store.get(), lowerName); break; + case ESM::REC_LEVC: create (store.get(), lowerName); break; + case ESM::REC_LEVI: create (store.get(), lowerName); break; + case ESM::REC_LIGH: create (store.get(), lowerName); break; + case ESM::REC_LOCK: create (store.get(), lowerName); break; + case ESM::REC_MISC: create (store.get(), lowerName); break; + case ESM::REC_NPC_: create (store.get(), lowerName); break; + case ESM::REC_PROB: create (store.get(), lowerName); break; + case ESM::REC_REPA: create (store.get(), lowerName); break; + case ESM::REC_STAT: create (store.get(), lowerName); break; + case ESM::REC_WEAP: create (store.get(), lowerName); break; + + case 0: + throw std::logic_error ("failed to create manual cell ref for " + lowerName + " (unknown ID)"); + + default: + throw std::logic_error ("failed to create manual cell ref for " + lowerName + " (unknown type)"); + } // initialise ESM::CellRef& cellRef = mPtr.getCellRef(); - cellRef.mRefID = Misc::StringUtils::lowerCase (name); + cellRef.mRefID = lowerName; cellRef.mRefNum.mIndex = 0; cellRef.mRefNum.mContentFile = -1; cellRef.mScale = 1; From e51300989cbb8ff0bb341da67bd7147c0cd5e3f9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 22 May 2014 22:15:20 +0200 Subject: [PATCH 011/151] Handle NiBSPArrayController as alias for NiParticleSystemController The differences (if any) are unknown. NiBSPArrayController is used by the Atronach_Fire.nif model. Its particles are now visible, but they don't look right yet. Need to handle NiAutoNormalParticlesData? --- components/nifogre/ogrenifloader.cpp | 3 ++- components/nifogre/skeleton.cpp | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index ce82446194..36d7508214 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -863,7 +863,8 @@ class NIFObjectLoader Nif::ControllerPtr ctrl = partnode->controller; while(!ctrl.empty()) { - if(ctrl->recType == Nif::RC_NiParticleSystemController && ctrl->flags & Nif::NiNode::ControllerFlag_Active) + if((ctrl->recType == Nif::RC_NiParticleSystemController || ctrl->recType == Nif::RC_NiBSPArrayController) + && ctrl->flags & Nif::NiNode::ControllerFlag_Active) { const Nif::NiParticleSystemController *partctrl = static_cast(ctrl.getPtr()); diff --git a/components/nifogre/skeleton.cpp b/components/nifogre/skeleton.cpp index c0482cf5e3..26647e595d 100644 --- a/components/nifogre/skeleton.cpp +++ b/components/nifogre/skeleton.cpp @@ -42,6 +42,7 @@ void NIFSkeletonLoader::buildBones(Ogre::Skeleton *skel, const Nif::Node *node, while(!ctrl.empty()) { if(!(ctrl->recType == Nif::RC_NiParticleSystemController || + ctrl->recType == Nif::RC_NiBSPArrayController || ctrl->recType == Nif::RC_NiVisController || ctrl->recType == Nif::RC_NiUVController || ctrl->recType == Nif::RC_NiKeyframeController || From df8e095c83ac2655cee0082d3f06c8419fc29e24 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 22 May 2014 23:27:54 +0200 Subject: [PATCH 012/151] Small cleanup --- apps/openmw/mwdialogue/filter.cpp | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index 5bdf80593b..863a0f2ffc 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -264,15 +264,7 @@ int MWDialogue::Filter::getSelectStructInteger (const SelectWrapper& select) con { MWWorld::ContainerStore& store = MWWorld::Class::get (player).getContainerStore (player); - int sum = 0; - - std::string name = select.getName(); - - for (MWWorld::ContainerStoreIterator iter (store.begin()); iter!=store.end(); ++iter) - if (Misc::StringUtils::ciEqual(iter->getCellRef().mRefID, name)) - sum += iter->getRefData().getCount(); - - return sum; + return store.count(select.getName()); } case SelectWrapper::Function_Dead: From a2f156be8e506503628c424e695ede9834f234b3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 22 May 2014 23:33:34 +0200 Subject: [PATCH 013/151] Prevent magic bolts from colliding with their caster --- apps/openmw/mwworld/projectilemanager.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 266b566f70..bf0fb75795 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -152,6 +152,10 @@ namespace MWWorld MWWorld::Ptr obstacle = MWBase::Environment::get().getWorld()->searchPtrViaHandle(cIt->second); MWWorld::Ptr caster = MWBase::Environment::get().getWorld()->searchPtrViaActorId(it->mActorId); + + if (!obstacle.isEmpty() && obstacle == caster) + continue; + if (caster.isEmpty()) caster = obstacle; From f4334da42ec0076c073aed1a3aec6a4a17f1ba5a Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 23 May 2014 09:32:34 +0200 Subject: [PATCH 014/151] 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 3718847ffc0c77db9d979d1a4aed7f351c92a96e Mon Sep 17 00:00:00 2001 From: cc9cii Date: Fri, 23 May 2014 21:07:01 +1000 Subject: [PATCH 015/151] Disable video for Windows until the crash issues are fixed. --- apps/openmw/mwrender/videoplayer.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 82400aac43..b1519b9d2c 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -1080,6 +1080,11 @@ VideoPlayer::~VideoPlayer() void VideoPlayer::playVideo(const std::string &resourceName) { +#ifdef WIN32 + // FIXME: Need FFmpeg FLTP audio support for BIK video format + std::cout<<"Temporarily disabled, did not play \""+resourceName+"\""< Date: Fri, 23 May 2014 21:55:47 +1000 Subject: [PATCH 016/151] Enable video but without sound. --- apps/openmw/mwrender/videoplayer.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index b1519b9d2c..9fd1cee961 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -970,8 +970,13 @@ void VideoState::init(const std::string& resourceName) MWBase::Environment::get().getSoundManager()->pauseSounds(); this->external_clock_base = av_gettime(); +#ifdef WIN32 + // FIXME: Need FFmpeg FLTP audio support for BIK video format + std::cout<<"Sound temporarily disabled for \""+resourceName+"\""<= 0) this->stream_open(audio_index, this->format_ctx); +#endif if(video_index >= 0) { this->stream_open(video_index, this->format_ctx); @@ -1080,11 +1085,6 @@ VideoPlayer::~VideoPlayer() void VideoPlayer::playVideo(const std::string &resourceName) { -#ifdef WIN32 - // FIXME: Need FFmpeg FLTP audio support for BIK video format - std::cout<<"Temporarily disabled, did not play \""+resourceName+"\""< Date: Fri, 23 May 2014 16:07:02 +0200 Subject: [PATCH 017/151] Fix missing include --- apps/openmw/mwworld/projectilemanager.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index bf0fb75795..12cca27545 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -1,6 +1,7 @@ #include "projectilemanager.hpp" #include +#include #include From f09c8ddc9e3ba3258b3af1faafdb0800bd8ebfc2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 23 May 2014 16:39:42 +0200 Subject: [PATCH 018/151] Remove a pointless assert --- apps/openmw/mwmechanics/creaturestats.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/openmw/mwmechanics/creaturestats.cpp b/apps/openmw/mwmechanics/creaturestats.cpp index 3648877fdd..3ef6ff4df9 100644 --- a/apps/openmw/mwmechanics/creaturestats.cpp +++ b/apps/openmw/mwmechanics/creaturestats.cpp @@ -102,7 +102,6 @@ namespace MWMechanics Stat CreatureStats::getAiSetting (AiSetting index) const { - assert (index>=0 && index<4); return mAiSettings[index]; } @@ -220,7 +219,6 @@ namespace MWMechanics void CreatureStats::setAiSetting (AiSetting index, Stat value) { - assert (index>=0 && index<4); mAiSettings[index] = value; } From 1d8da957564b4dd6823935961e7c58ecdfdef0fc Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 24 May 2014 14:47:51 +0200 Subject: [PATCH 019/151] Warning fix --- apps/openmw/mwrender/localmap.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 0d32dd0ef0..2b0323675e 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -353,7 +353,7 @@ void LocalMap::loadFogOfWar (const std::string& texturePrefix, ESM::FogTexture& Ogre::Image image; image.load(stream, "tga"); - if (image.getWidth() != sFogOfWarResolution || image.getHeight() != sFogOfWarResolution) + if (int(image.getWidth()) != sFogOfWarResolution || int(image.getHeight()) != sFogOfWarResolution) throw std::runtime_error("fog texture size mismatch"); std::string texName = texturePrefix + "_fog"; From a05c8fd3ceefa0d0f0ff287023eb332217552315 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 24 May 2014 14:48:37 +0200 Subject: [PATCH 020/151] Make applyEnchantment return the record ID instead of modifying Ptr --- apps/openmw/mwclass/armor.cpp | 5 ++--- apps/openmw/mwclass/armor.hpp | 3 ++- apps/openmw/mwclass/book.cpp | 5 ++--- apps/openmw/mwclass/book.hpp | 3 ++- apps/openmw/mwclass/clothing.cpp | 5 ++--- apps/openmw/mwclass/clothing.hpp | 3 ++- apps/openmw/mwclass/weapon.cpp | 5 ++--- apps/openmw/mwclass/weapon.hpp | 3 ++- apps/openmw/mwmechanics/enchanting.cpp | 10 ++-------- apps/openmw/mwmechanics/enchanting.hpp | 1 - apps/openmw/mwworld/class.cpp | 2 +- apps/openmw/mwworld/class.hpp | 3 ++- 12 files changed, 21 insertions(+), 27 deletions(-) diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 26d1cab6d2..d7dae97a5b 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -272,7 +272,7 @@ namespace MWClass return ref->mBase->mEnchant; } - void Armor::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const + std::string Armor::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const { MWWorld::LiveCellRef *ref = ptr.get(); @@ -283,8 +283,7 @@ namespace MWClass newItem.mData.mEnchant=enchCharge; newItem.mEnchant=enchId; const ESM::Armor *record = MWBase::Environment::get().getWorld()->createRecord (newItem); - ref->mBase = record; - ref->mRef.mRefID = record->mId; + return record->mId; } std::pair Armor::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index 17cfca4534..e9164f920b 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -67,7 +67,8 @@ namespace MWClass virtual std::string getEnchantment (const MWWorld::Ptr& ptr) const; ///< @return the enchantment ID if the object is enchanted, otherwise an empty string - virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; + virtual std::string applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; + ///< Creates a new record using \a ptr as template, with the given name and the given enchantment applied to it. virtual std::pair canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const; ///< Return 0 if player cannot equip item. 1 if can equip. 2 if it's twohanded weapon. 3 if twohanded weapon conflicts with that. \n diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index 183d91ca1f..338a7ba0d7 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -159,7 +159,7 @@ namespace MWClass return ref->mBase->mEnchant; } - void Book::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const + std::string Book::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const { MWWorld::LiveCellRef *ref = ptr.get(); @@ -171,8 +171,7 @@ namespace MWClass newItem.mData.mEnchant=enchCharge; newItem.mEnchant=enchId; const ESM::Book *record = MWBase::Environment::get().getWorld()->createRecord (newItem); - ref->mBase = record; - ref->mRef.mRefID = record->mId; + return record->mId; } boost::shared_ptr Book::use (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/book.hpp b/apps/openmw/mwclass/book.hpp index 79b823fa9f..b60ef41d64 100644 --- a/apps/openmw/mwclass/book.hpp +++ b/apps/openmw/mwclass/book.hpp @@ -51,7 +51,8 @@ namespace MWClass virtual std::string getEnchantment (const MWWorld::Ptr& ptr) const; ///< @return the enchantment ID if the object is enchanted, otherwise an empty string - virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; + virtual std::string applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; + ///< Creates a new record using \a ptr as template, with the given name and the given enchantment applied to it. virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; ///< Generate action for using via inventory menu diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index a174f69a77..f596f60deb 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -215,7 +215,7 @@ namespace MWClass return ref->mBase->mEnchant; } - void Clothing::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const + std::string Clothing::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const { MWWorld::LiveCellRef *ref = ptr.get(); @@ -226,8 +226,7 @@ namespace MWClass newItem.mData.mEnchant=enchCharge; newItem.mEnchant=enchId; const ESM::Clothing *record = MWBase::Environment::get().getWorld()->createRecord (newItem); - ref->mBase = record; - ref->mRef.mRefID = record->mId; + return record->mId; } std::pair Clothing::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index a73b2c1907..052928238e 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -59,7 +59,8 @@ namespace MWClass virtual std::string getEnchantment (const MWWorld::Ptr& ptr) const; ///< @return the enchantment ID if the object is enchanted, otherwise an empty string - virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; + virtual std::string applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; + ///< Creates a new record using \a ptr as template, with the given name and the given enchantment applied to it. virtual std::pair canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const; ///< Return 0 if player cannot equip item. 1 if can equip. 2 if it's twohanded weapon. 3 if twohanded weapon conflicts with that. diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index 146251ca29..5edf22b008 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -372,7 +372,7 @@ namespace MWClass return ref->mBase->mEnchant; } - void Weapon::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const + std::string Weapon::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const { MWWorld::LiveCellRef *ref = ptr.get(); @@ -383,8 +383,7 @@ namespace MWClass newItem.mData.mEnchant=enchCharge; newItem.mEnchant=enchId; const ESM::Weapon *record = MWBase::Environment::get().getWorld()->createRecord (newItem); - ref->mBase = record; - ref->mRef.mRefID = record->mId; + return record->mId; } std::pair Weapon::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index db44cd2b71..97ee102911 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -68,7 +68,8 @@ namespace MWClass virtual std::string getEnchantment (const MWWorld::Ptr& ptr) const; ///< @return the enchantment ID if the object is enchanted, otherwise an empty string - virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; + virtual std::string applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; + ///< Creates a new record using \a ptr as template, with the given name and the given enchantment applied to it. virtual std::pair canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const; ///< Return 0 if player cannot equip item. 1 if can equip. 2 if it's twohanded weapon. 3 if twohanded weapon conflicts with that. diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index 23246c2945..9c5c9dbb9d 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -20,12 +20,10 @@ namespace MWMechanics if(!itemEmpty()) { mObjectType = mOldItemPtr.getTypeName(); - mOldItemId = mOldItemPtr.getCellRef().mRefID; } else { mObjectType=""; - mOldItemId=""; } } @@ -78,17 +76,13 @@ namespace MWMechanics enchantment.mData.mCost = getEnchantPoints(); enchantment.mEffects = mEffectList; - // Create a new item - MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), mOldItemId, 1); - const MWWorld::Ptr& newItemPtr = ref.getPtr(); - // Apply the enchantment const ESM::Enchantment *enchantmentPtr = MWBase::Environment::get().getWorld()->createRecord (enchantment); - newItemPtr.getClass().applyEnchantment(newItemPtr, enchantmentPtr->mId, getGemCharge(), mNewItemName); + std::string newItemId = mOldItemPtr.getClass().applyEnchantment(mOldItemPtr, enchantmentPtr->mId, getGemCharge(), mNewItemName); // Add the new item to player inventory and remove the old one store.remove(mOldItemPtr, 1, player); - store.add(newItemPtr, 1, player); + store.add(newItemId, 1, player); if(!mSelfEnchanting) payForEnchantment(); diff --git a/apps/openmw/mwmechanics/enchanting.hpp b/apps/openmw/mwmechanics/enchanting.hpp index ae0b25a4a2..01ca1e0e1d 100644 --- a/apps/openmw/mwmechanics/enchanting.hpp +++ b/apps/openmw/mwmechanics/enchanting.hpp @@ -21,7 +21,6 @@ namespace MWMechanics std::string mNewItemName; std::string mObjectType; - std::string mOldItemId; public: Enchanting(); diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 6629f84f91..100e758f24 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -304,7 +304,7 @@ namespace MWWorld return ""; } - void Class::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const + std::string Class::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const { throw std::runtime_error ("class can't be enchanted"); } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index b47028e01f..54cea9ab01 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -278,7 +278,8 @@ namespace MWWorld virtual std::string getModel(const MWWorld::Ptr &ptr) const; - virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; + virtual std::string applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; + ///< Creates a new record using \a ptr as template, with the given name and the given enchantment applied to it. virtual std::pair canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const; ///< Return 0 if player cannot equip item. 1 if can equip. 2 if it's twohanded weapon. 3 if twohanded weapon conflicts with that. From 4f94a31b5422545a8ed7b76920c132192a9c5a9d Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 25 May 2014 07:50:19 +1000 Subject: [PATCH 021/151] Fix crash starting a new game. --- apps/openmw/mwscript/cellextensions.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/openmw/mwscript/cellextensions.cpp b/apps/openmw/mwscript/cellextensions.cpp index 825d62efb5..ac175634bd 100644 --- a/apps/openmw/mwscript/cellextensions.cpp +++ b/apps/openmw/mwscript/cellextensions.cpp @@ -88,6 +88,12 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { + if (!MWBase::Environment::get().getWorld()->getPlayerPtr().isInCell()) + { + runtime.push (0); + return; + } + bool interior = !MWBase::Environment::get().getWorld()->getPlayerPtr().getCell()->getCell()->isExterior(); From d2794165bac7e4993510d1b9bf95f90fe7312508 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 25 May 2014 18:56:50 +1000 Subject: [PATCH 022/151] Disable binkaudio sound for FFmpeg libavocdec versions below 54.55.xxx (Windows x64) and 54.10.xxx (Windows 32bit). Later versions are all allowed, but due to sample formats there will be no sound and this message will be shown on the console "Sound Error: Unsupported sample format: fltp" --- apps/openmw/mwrender/videoplayer.cpp | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 82400aac43..fe97d77d4c 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -50,6 +50,29 @@ extern "C" #endif } +#ifdef _WIN32 + // Decide whether to play binkaudio. + #include + // libavcodec versions 54.10.100 (or maybe earlier) to 54.54.100 potentially crashes Windows 64bit. + // From version 54.56 or higher, there's no sound due to the encoding format changing from S16 to FLTP + // (see https://gitorious.org/ffmpeg/ffmpeg/commit/7bfd1766d1c18f07b0a2dd042418a874d49ea60d and + // http://git.videolan.org/?p=ffmpeg.git;a=commitdiff;h=3049d5b9b32845c86aa5588bb3352bdeb2edfdb2;hp=43c6b45a53a186a187f7266e4d6bd3c2620519f1), + // but does not crash (or at least no known crash). + #if (LIBAVCODEC_VERSION_MAJOR > 54) + #define FFMPEG_PLAY_BINKAUDIO + #else + #ifdef _WIN64 + #if ((LIBAVCODEC_VERSION_MAJOR == 54) && (LIBAVCODEC_VERSION_MINOR >= 55)) + #define FFMPEG_PLAY_BINKAUDIO + #endif + #else + #if ((LIBAVCODEC_VERSION_MAJOR == 54) && (LIBAVCODEC_VERSION_MINOR >= 10)) + #define FFMPEG_PLAY_BINKAUDIO + #endif + #endif + #endif +#endif + #define MAX_AUDIOQ_SIZE (5 * 16 * 1024) #define MAX_VIDEOQ_SIZE (5 * 256 * 1024) #define AV_SYNC_THRESHOLD 0.01 @@ -970,8 +993,12 @@ void VideoState::init(const std::string& resourceName) MWBase::Environment::get().getSoundManager()->pauseSounds(); this->external_clock_base = av_gettime(); +#if !defined(_WIN32) || defined(FFMPEG_PLAY_BINKAUDIO) if(audio_index >= 0) this->stream_open(audio_index, this->format_ctx); +#else + std::cout<<"FFmpeg sound disabled for \""+resourceName+"\""<= 0) { this->stream_open(video_index, this->format_ctx); From 039398c8aeecc54b627d6294b6c8e11c9abda133 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 25 May 2014 14:13:07 +0200 Subject: [PATCH 023/151] Basic RefData and CellRef change tracking Wrapped item charge handling in getItemHealth function --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwclass/activator.cpp | 4 +- apps/openmw/mwclass/apparatus.cpp | 4 +- apps/openmw/mwclass/armor.cpp | 15 +- apps/openmw/mwclass/book.cpp | 4 +- apps/openmw/mwclass/clothing.cpp | 6 +- apps/openmw/mwclass/container.cpp | 34 ++-- apps/openmw/mwclass/creature.cpp | 34 ++-- apps/openmw/mwclass/creaturelevlist.cpp | 4 +- apps/openmw/mwclass/door.cpp | 42 ++-- apps/openmw/mwclass/ingredient.cpp | 4 +- apps/openmw/mwclass/light.cpp | 4 +- apps/openmw/mwclass/lockpick.cpp | 11 +- apps/openmw/mwclass/misc.cpp | 37 ++-- apps/openmw/mwclass/npc.cpp | 47 ++--- apps/openmw/mwclass/potion.cpp | 4 +- apps/openmw/mwclass/probe.cpp | 11 +- apps/openmw/mwclass/repair.cpp | 11 +- apps/openmw/mwclass/weapon.cpp | 15 +- apps/openmw/mwgui/console.cpp | 2 +- apps/openmw/mwgui/enchantingdialog.cpp | 2 +- apps/openmw/mwgui/hud.cpp | 2 +- apps/openmw/mwgui/inventoryitemmodel.cpp | 4 +- apps/openmw/mwgui/inventorywindow.cpp | 6 +- apps/openmw/mwgui/merchantrepair.cpp | 4 +- apps/openmw/mwgui/pickpocketitemmodel.cpp | 4 +- apps/openmw/mwgui/quickkeysmenu.cpp | 11 +- apps/openmw/mwgui/recharge.cpp | 14 +- apps/openmw/mwgui/repair.cpp | 4 +- apps/openmw/mwgui/sortfilteritemmodel.cpp | 2 +- apps/openmw/mwgui/spellwindow.cpp | 2 +- apps/openmw/mwgui/tooltips.cpp | 2 +- apps/openmw/mwgui/tradeitemmodel.cpp | 6 +- apps/openmw/mwgui/tradewindow.cpp | 2 +- apps/openmw/mwgui/windowmanagerimp.cpp | 8 +- apps/openmw/mwmechanics/actors.cpp | 22 +-- apps/openmw/mwmechanics/aiavoiddoor.cpp | 5 - apps/openmw/mwmechanics/aiavoiddoor.hpp | 3 - apps/openmw/mwmechanics/aicombat.cpp | 4 +- apps/openmw/mwmechanics/aipackage.cpp | 2 +- apps/openmw/mwmechanics/combat.cpp | 9 +- apps/openmw/mwmechanics/enchanting.cpp | 4 +- .../mwmechanics/mechanicsmanagerimp.cpp | 8 +- apps/openmw/mwmechanics/obstacle.cpp | 2 +- apps/openmw/mwmechanics/repair.cpp | 14 +- apps/openmw/mwmechanics/security.cpp | 26 +-- apps/openmw/mwmechanics/spellcasting.cpp | 22 +-- apps/openmw/mwrender/actors.cpp | 4 +- apps/openmw/mwrender/animation.cpp | 6 +- apps/openmw/mwrender/objects.cpp | 4 +- apps/openmw/mwscript/cellextensions.cpp | 5 + apps/openmw/mwscript/containerextensions.cpp | 8 +- apps/openmw/mwscript/miscextensions.cpp | 16 +- .../mwscript/transformationextensions.cpp | 26 +-- apps/openmw/mwworld/actiontrap.cpp | 2 +- apps/openmw/mwworld/cellref.cpp | 185 ++++++++++++++++++ apps/openmw/mwworld/cellref.hpp | 99 ++++++++++ apps/openmw/mwworld/cellreflist.hpp | 2 +- apps/openmw/mwworld/cellstore.cpp | 14 +- apps/openmw/mwworld/class.cpp | 8 + apps/openmw/mwworld/class.hpp | 5 +- apps/openmw/mwworld/containerstore.cpp | 60 +++--- apps/openmw/mwworld/inventorystore.cpp | 22 +-- apps/openmw/mwworld/livecellref.cpp | 4 +- apps/openmw/mwworld/livecellref.hpp | 8 +- apps/openmw/mwworld/manualref.hpp | 31 ++- apps/openmw/mwworld/physicssystem.cpp | 2 +- apps/openmw/mwworld/player.cpp | 6 +- apps/openmw/mwworld/projectilemanager.cpp | 8 +- apps/openmw/mwworld/ptr.cpp | 2 +- apps/openmw/mwworld/ptr.hpp | 2 +- apps/openmw/mwworld/refdata.cpp | 24 ++- apps/openmw/mwworld/refdata.hpp | 5 + apps/openmw/mwworld/scene.cpp | 12 +- apps/openmw/mwworld/worldimp.cpp | 32 +-- components/esm/cellref.cpp | 2 +- components/esm/cellref.hpp | 22 ++- components/esm/loadcell.cpp | 6 +- components/esm/loadcell.hpp | 6 +- 79 files changed, 720 insertions(+), 407 deletions(-) create mode 100644 apps/openmw/mwworld/cellref.cpp create mode 100644 apps/openmw/mwworld/cellref.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 9e959a986d..8496b47a4a 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -57,7 +57,7 @@ add_openmw_dir (mwworld cells localscripts customdata weather inventorystore ptr actionopen actionread actionequip timestamp actionalchemy cellstore actionapply actioneat esmstore store recordcmp fallback actionrepair actionsoulgem livecellref actiondoor - contentloader esmloader omwloader actiontrap cellreflist projectilemanager + contentloader esmloader omwloader actiontrap cellreflist projectilemanager cellref ) add_openmw_dir (mwclass diff --git a/apps/openmw/mwclass/activator.cpp b/apps/openmw/mwclass/activator.cpp index fe9368b446..043aadd359 100644 --- a/apps/openmw/mwclass/activator.cpp +++ b/apps/openmw/mwclass/activator.cpp @@ -97,8 +97,8 @@ namespace MWClass std::string text; if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { - text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner"); - text += MWGui::ToolTips::getMiscString(ref->mRef.mFaction, "Faction"); + text += MWGui::ToolTips::getMiscString(ptr.getCellRef().getOwner(), "Owner"); + text += MWGui::ToolTips::getMiscString(ptr.getCellRef().getFaction(), "Faction"); text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script"); } info.text = text; diff --git a/apps/openmw/mwclass/apparatus.cpp b/apps/openmw/mwclass/apparatus.cpp index 8580d61ce0..947a9cb948 100644 --- a/apps/openmw/mwclass/apparatus.cpp +++ b/apps/openmw/mwclass/apparatus.cpp @@ -127,8 +127,8 @@ namespace MWClass text += MWGui::ToolTips::getValueString(getValue(ptr), "#{sValue}"); if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { - text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner"); - text += MWGui::ToolTips::getMiscString(ref->mRef.mFaction, "Faction"); + text += MWGui::ToolTips::getMiscString(ptr.getCellRef().getOwner(), "Owner"); + text += MWGui::ToolTips::getMiscString(ptr.getCellRef().getFaction(), "Faction"); text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script"); } info.text = text; diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index d7dae97a5b..825b14978f 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -168,10 +168,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - if (ptr.getCellRef().mCharge == -1) - return ref->mBase->mData.mValue; - else - return ref->mBase->mData.mValue * (static_cast(ptr.getCellRef().mCharge) / getItemMaxHealth(ptr)); + return ref->mBase->mData.mValue * (static_cast(getItemHealth(ptr)) / getItemMaxHealth(ptr)); } void Armor::registerSelf() @@ -242,7 +239,7 @@ namespace MWClass text += "\n#{sArmorRating}: " + MWGui::ToolTips::toString(ref->mBase->mData.mArmor); - int remainingHealth = (ptr.getCellRef().mCharge != -1) ? ptr.getCellRef().mCharge : ref->mBase->mData.mHealth; + int remainingHealth = getItemHealth(ptr); text += "\n#{sCondition}: " + MWGui::ToolTips::toString(remainingHealth) + "/" + MWGui::ToolTips::toString(ref->mBase->mData.mHealth); @@ -250,14 +247,14 @@ namespace MWClass text += MWGui::ToolTips::getValueString(getValue(ptr), "#{sValue}"); if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { - text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner"); - text += MWGui::ToolTips::getMiscString(ref->mRef.mFaction, "Faction"); + text += MWGui::ToolTips::getMiscString(ptr.getCellRef().getOwner(), "Owner"); + text += MWGui::ToolTips::getMiscString(ptr.getCellRef().getFaction(), "Faction"); text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script"); } info.enchant = ref->mBase->mEnchant; if (!info.enchant.empty()) - info.remainingEnchantCharge = ptr.getCellRef().mEnchantmentCharge; + info.remainingEnchantCharge = ptr.getCellRef().getEnchantmentCharge(); info.text = text; @@ -290,7 +287,7 @@ namespace MWClass { MWWorld::InventoryStore& invStore = npc.getClass().getInventoryStore(npc); - if (ptr.getCellRef().mCharge == 0) + if (ptr.getCellRef().getCharge() == 0) return std::make_pair(0, "#{sInventoryMessage1}"); // slots that this item can be equipped in diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index 338a7ba0d7..0cc2e60207 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -139,8 +139,8 @@ namespace MWClass text += MWGui::ToolTips::getValueString(getValue(ptr), "#{sValue}"); if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { - text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner"); - text += MWGui::ToolTips::getMiscString(ref->mRef.mFaction, "Faction"); + text += MWGui::ToolTips::getMiscString(ptr.getCellRef().getOwner(), "Owner"); + text += MWGui::ToolTips::getMiscString(ptr.getCellRef().getFaction(), "Faction"); text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script"); } diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index f596f60deb..c0362188b8 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -193,14 +193,14 @@ namespace MWClass text += MWGui::ToolTips::getValueString(getValue(ptr), "#{sValue}"); if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { - text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner"); - text += MWGui::ToolTips::getMiscString(ref->mRef.mFaction, "Faction"); + text += MWGui::ToolTips::getMiscString(ptr.getCellRef().getOwner(), "Owner"); + text += MWGui::ToolTips::getMiscString(ptr.getCellRef().getFaction(), "Faction"); text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script"); } info.enchant = ref->mBase->mEnchant; if (!info.enchant.empty()) - info.remainingEnchantCharge = ptr.getCellRef().mEnchantmentCharge; + info.remainingEnchantCharge = ptr.getCellRef().getEnchantmentCharge(); info.text = text; diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index 62734c03de..9498ea52df 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -53,7 +53,7 @@ namespace MWClass ptr.get(); data->mContainerStore.fill( - ref->mBase->mInventory, ptr.getCellRef().mOwner, ptr.getCellRef().mFaction, MWBase::Environment::get().getWorld()->getStore()); + ref->mBase->mInventory, ptr.getCellRef().getOwner(), ptr.getCellRef().getFaction(), MWBase::Environment::get().getWorld()->getStore()); // store ptr.getRefData().setCustomData (data.release()); @@ -75,7 +75,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); const ESM::InventoryList& list = ref->mBase->mInventory; MWWorld::ContainerStore& store = getContainerStore(ptr); - store.restock(list, ptr, ptr.getCellRef().mOwner, ptr.getCellRef().mFaction); + store.restock(list, ptr, ptr.getCellRef().getOwner(), ptr.getCellRef().getFaction()); } void Container::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const @@ -129,16 +129,16 @@ namespace MWClass MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayerPtr(); MWWorld::InventoryStore& invStore = player.getClass().getInventoryStore(player); - bool needKey = ptr.getCellRef().mLockLevel > 0; + bool needKey = ptr.getCellRef().getLockLevel() > 0; bool hasKey = false; std::string keyName; // make key id lowercase - std::string keyId = ptr.getCellRef().mKey; + std::string keyId = ptr.getCellRef().getKey(); Misc::StringUtils::toLower(keyId); for (MWWorld::ContainerStoreIterator it = invStore.begin(); it != invStore.end(); ++it) { - std::string refId = it->getCellRef().mRefID; + std::string refId = it->getCellRef().getRefId(); Misc::StringUtils::toLower(refId); if (refId == keyId) { @@ -152,13 +152,13 @@ namespace MWClass MWBase::Environment::get().getWindowManager ()->messageBox (keyName + " #{sKeyUsed}"); unlock(ptr); // using a key disarms the trap - ptr.getCellRef().mTrap = ""; + ptr.getCellRef().setTrap(""); } if (!needKey || hasKey) { - if(ptr.getCellRef().mTrap.empty()) + if(ptr.getCellRef().getTrap().empty()) { boost::shared_ptr action (new MWWorld::ActionOpen(ptr)); return action; @@ -166,7 +166,7 @@ namespace MWClass else { // Activate trap - boost::shared_ptr action(new MWWorld::ActionTrap(actor, ptr.getCellRef().mTrap, ptr)); + boost::shared_ptr action(new MWWorld::ActionTrap(actor, ptr.getCellRef().getTrap(), ptr)); action->setSound(trapActivationSound); return action; } @@ -227,16 +227,16 @@ namespace MWClass info.caption = ref->mBase->mName; std::string text; - if (ref->mRef.mLockLevel > 0) - text += "\n#{sLockLevel}: " + MWGui::ToolTips::toString(ref->mRef.mLockLevel); - else if (ref->mRef.mLockLevel < 0) + if (ptr.getCellRef().getLockLevel() > 0) + text += "\n#{sLockLevel}: " + MWGui::ToolTips::toString(ptr.getCellRef().getLockLevel()); + else if (ptr.getCellRef().getLockLevel() < 0) text += "\n#{sUnlocked}"; - if (ref->mRef.mTrap != "") + if (ptr.getCellRef().getTrap() != "") text += "\n#{sTrapped}"; if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { - text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner"); - text += MWGui::ToolTips::getMiscString(ref->mRef.mFaction, "Faction"); + text += MWGui::ToolTips::getMiscString(ptr.getCellRef().getOwner(), "Owner"); + text += MWGui::ToolTips::getMiscString(ptr.getCellRef().getFaction(), "Faction"); text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script"); } @@ -261,14 +261,14 @@ namespace MWClass void Container::lock (const MWWorld::Ptr& ptr, int lockLevel) const { if(lockLevel!=0) - ptr.getCellRef().mLockLevel = abs(lockLevel); //Changes lock to locklevel, in positive + ptr.getCellRef().setLockLevel(abs(lockLevel)); //Changes lock to locklevel, in positive else - ptr.getCellRef().mLockLevel = abs(ptr.getCellRef().mLockLevel); //No locklevel given, just flip the oriional one + ptr.getCellRef().setLockLevel(abs(ptr.getCellRef().getLockLevel())); //No locklevel given, just flip the original one } void Container::unlock (const MWWorld::Ptr& ptr) const { - ptr.getCellRef().mLockLevel = -abs(ptr.getCellRef().mLockLevel); //Makes lockLevel negative + ptr.getCellRef().setLockLevel(-abs(ptr.getCellRef().getLockLevel())); //Makes lockLevel negative } diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 7e484f9d48..1a6e4e321d 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -291,20 +291,24 @@ namespace MWClass weaponDamage *= 0.5f + (stats.getAttribute(ESM::Attribute::Luck).getModified() / 100.0f); if(weaphashealth) { - int weapmaxhealth = weapon.get()->mBase->mData.mHealth; - if(weapon.getCellRef().mCharge == -1) - weapon.getCellRef().mCharge = weapmaxhealth; - weaponDamage *= float(weapon.getCellRef().mCharge) / weapmaxhealth; + int weapmaxhealth = weapon.getClass().getItemMaxHealth(weapon); + int weaphealth = weapon.getClass().getItemHealth(weapon); + weaponDamage *= float(weaphealth) / weapmaxhealth; + + if (!MWBase::Environment::get().getWorld()->getGodModeState()) + { + // Reduce weapon charge by at least one, but cap at 0 + weaphealth -= std::min(std::max(1, + (int)(damage * gmst.find("fWeaponDamageMult")->getFloat())), weaphealth); + + weapon.getCellRef().setCharge(weaphealth); + } + + // Weapon broken? unequip it + if (weapon.getCellRef().getCharge() == 0) + weapon = *getInventoryStore(ptr).unequipItem(weapon, ptr); } - if (!MWBase::Environment::get().getWorld()->getGodModeState()) - weapon.getCellRef().mCharge -= std::min(std::max(1, - (int)(damage * gmst.find("fWeaponDamageMult")->getFloat())), weapon.getCellRef().mCharge); - - // Weapon broken? unequip it - if (weapon.getCellRef().mCharge == 0) - weapon = *getInventoryStore(ptr).unequipItem(weapon, ptr); - damage += weaponDamage; } @@ -825,14 +829,14 @@ namespace MWClass { // Note we do not respawn moved references in the cell they were moved to. Instead they are respawned in the original cell. // This also means we cannot respawn dynamically placed references with no content file connection. - if (ptr.getCellRef().mRefNum.mContentFile != -1) + if (ptr.getCellRef().getRefNum().mContentFile != -1) { if (ptr.getRefData().getCount() == 0) ptr.getRefData().setCount(1); // Reset to original position ESM::Position& pos = ptr.getRefData().getPosition(); - pos = ptr.getCellRef().mPos; + pos = ptr.getCellRef().getPosition(); ptr.getRefData().setCustomData(NULL); } @@ -844,7 +848,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); const ESM::InventoryList& list = ref->mBase->mInventory; MWWorld::ContainerStore& store = getContainerStore(ptr); - store.restock(list, ptr, ptr.getCellRef().mRefID, ptr.getCellRef().mFaction); + store.restock(list, ptr, ptr.getCellRef().getRefId(), ptr.getCellRef().getFaction()); } const ESM::GameSetting* Creature::fMinWalkSpeedCreature; diff --git a/apps/openmw/mwclass/creaturelevlist.cpp b/apps/openmw/mwclass/creaturelevlist.cpp index fea30735c6..7843048044 100644 --- a/apps/openmw/mwclass/creaturelevlist.cpp +++ b/apps/openmw/mwclass/creaturelevlist.cpp @@ -73,8 +73,8 @@ namespace MWClass const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); MWWorld::ManualRef ref(store, id); - ref.getPtr().getCellRef().mPos = ptr.getCellRef().mPos; - MWWorld::Ptr placed = MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(), ptr.getCell() , ptr.getCellRef().mPos); + ref.getPtr().getCellRef().setPosition(ptr.getCellRef().getPosition()); + MWWorld::Ptr placed = MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(), ptr.getCell() , ptr.getCellRef().getPosition()); customData.mSpawnActorId = placed.getClass().getCreatureStats(placed).getActorId(); customData.mSpawn = false; } diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 27903c4103..12645c9f39 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -83,8 +83,8 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - if (ref->mRef.mTeleport && !ref->mRef.mDestCell.empty()) // TODO doors that lead to exteriors - return ref->mRef.mDestCell; + if (ptr.getCellRef().getTeleport() && !ptr.getCellRef().getDestCell().empty()) // TODO doors that lead to exteriors + return ptr.getCellRef().getDestCell(); return ref->mBase->mName; } @@ -101,16 +101,16 @@ namespace MWClass MWWorld::ContainerStore &invStore = actor.getClass().getContainerStore(actor); - bool needKey = ptr.getCellRef().mLockLevel > 0; + bool needKey = ptr.getCellRef().getLockLevel() > 0; bool hasKey = false; std::string keyName; // make key id lowercase - std::string keyId = ptr.getCellRef().mKey; + std::string keyId = ptr.getCellRef().getKey(); Misc::StringUtils::toLower(keyId); for (MWWorld::ContainerStoreIterator it = invStore.begin(); it != invStore.end(); ++it) { - std::string refId = it->getCellRef().mRefID; + std::string refId = it->getCellRef().getRefId(); Misc::StringUtils::toLower(refId); if (refId == keyId) { @@ -125,22 +125,22 @@ namespace MWClass MWBase::Environment::get().getWindowManager()->messageBox(keyName + " #{sKeyUsed}"); unlock(ptr); //Call the function here. because that makes sense. // using a key disarms the trap - ptr.getCellRef().mTrap = ""; + ptr.getCellRef().getTrap() = ""; } if (!needKey || hasKey) { - if(!ptr.getCellRef().mTrap.empty()) + if(!ptr.getCellRef().getTrap().empty()) { // Trap activation - boost::shared_ptr action(new MWWorld::ActionTrap(actor, ptr.getCellRef().mTrap, ptr)); + boost::shared_ptr action(new MWWorld::ActionTrap(actor, ptr.getCellRef().getTrap(), ptr)); action->setSound(trapActivationSound); return action; } - if (ref->mRef.mTeleport) + if (ptr.getCellRef().getTeleport()) { - boost::shared_ptr action(new MWWorld::ActionTeleport (ref->mRef.mDestCell, ref->mRef.mDoorDest)); + boost::shared_ptr action(new MWWorld::ActionTeleport (ptr.getCellRef().getDestCell(), ptr.getCellRef().getDoorDest())); action->setSound(openSound); @@ -191,14 +191,14 @@ namespace MWClass void Door::lock (const MWWorld::Ptr& ptr, int lockLevel) const { if(lockLevel!=0) - ptr.getCellRef().mLockLevel = abs(lockLevel); //Changes lock to locklevel, in positive + ptr.getCellRef().setLockLevel(abs(lockLevel)); //Changes lock to locklevel, in positive else - ptr.getCellRef().mLockLevel = abs(ptr.getCellRef().mLockLevel); //No locklevel given, just flip the origional one + ptr.getCellRef().setLockLevel(abs(ptr.getCellRef().getLockLevel())); //No locklevel given, just flip the origional one } void Door::unlock (const MWWorld::Ptr& ptr) const { - ptr.getCellRef().mLockLevel = -abs(ptr.getCellRef().mLockLevel); //Makes lockLevel negative + ptr.getCellRef().setLockLevel(-abs(ptr.getCellRef().getLockLevel())); //Makes lockLevel negative } std::string Door::getScript (const MWWorld::Ptr& ptr) const @@ -234,17 +234,17 @@ namespace MWClass std::string text; - if (ref->mRef.mTeleport) + if (ptr.getCellRef().getTeleport()) { text += "\n#{sTo}"; text += "\n" + getDestination(*ref); } - if (ref->mRef.mLockLevel > 0) - text += "\n#{sLockLevel}: " + MWGui::ToolTips::toString(ref->mRef.mLockLevel); - else if (ref->mRef.mLockLevel < 0) + if (ptr.getCellRef().getLockLevel() > 0) + text += "\n#{sLockLevel}: " + MWGui::ToolTips::toString(ptr.getCellRef().getLockLevel()); + else if (ptr.getCellRef().getLockLevel() < 0) text += "\n#{sUnlocked}"; - if (ref->mRef.mTrap != "") + if (ptr.getCellRef().getTrap() != "") text += "\n#{sTrapped}"; if (MWBase::Environment::get().getWindowManager()->getFullHelp()) @@ -260,16 +260,16 @@ namespace MWClass const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); std::string dest; - if (door.mRef.mDestCell != "") + if (door.mRef.getDestCell() != "") { // door leads to an interior, use interior name as tooltip - dest = door.mRef.mDestCell; + dest = door.mRef.getDestCell(); } else { // door leads to exterior, use cell name (if any), otherwise translated region name int x,y; - MWBase::Environment::get().getWorld()->positionToIndex (door.mRef.mDoorDest.pos[0], door.mRef.mDoorDest.pos[1], x, y); + MWBase::Environment::get().getWorld()->positionToIndex (door.mRef.getDoorDest().pos[0], door.mRef.getDoorDest().pos[1], x, y); const ESM::Cell* cell = store.get().find(x,y); if (cell->mName != "") dest = cell->mName; diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index ebe41bb537..60c0efeb86 100644 --- a/apps/openmw/mwclass/ingredient.cpp +++ b/apps/openmw/mwclass/ingredient.cpp @@ -147,8 +147,8 @@ namespace MWClass text += MWGui::ToolTips::getValueString(getValue(ptr), "#{sValue}"); if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { - text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner"); - text += MWGui::ToolTips::getMiscString(ref->mRef.mFaction, "Faction"); + text += MWGui::ToolTips::getMiscString(ptr.getCellRef().getOwner(), "Owner"); + text += MWGui::ToolTips::getMiscString(ptr.getCellRef().getFaction(), "Faction"); text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script"); } diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 1b28a84625..fd45ec8592 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -187,8 +187,8 @@ namespace MWClass text += MWGui::ToolTips::getValueString(getValue(ptr), "#{sValue}"); if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { - text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner"); - text += MWGui::ToolTips::getMiscString(ref->mRef.mFaction, "Faction"); + text += MWGui::ToolTips::getMiscString(ptr.getCellRef().getOwner(), "Owner"); + text += MWGui::ToolTips::getMiscString(ptr.getCellRef().getFaction(), "Faction"); text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script"); } diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index 60ffec7b9b..19381a3fd5 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -86,10 +86,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - if (ptr.getCellRef().mCharge == -1) - return ref->mBase->mData.mValue; - else - return ref->mBase->mData.mValue * (static_cast(ptr.getCellRef().mCharge) / getItemMaxHealth(ptr)); + return ref->mBase->mData.mValue * (static_cast(getItemHealth(ptr)) / getItemMaxHealth(ptr)); } void Lockpick::registerSelf() @@ -136,7 +133,7 @@ namespace MWClass std::string text; - int remainingUses = (ptr.getCellRef().mCharge != -1) ? ptr.getCellRef().mCharge : ref->mBase->mData.mUses; + int remainingUses = getItemHealth(ptr); text += "\n#{sUses}: " + MWGui::ToolTips::toString(remainingUses); text += "\n#{sQuality}: " + MWGui::ToolTips::toString(ref->mBase->mData.mQuality); @@ -144,8 +141,8 @@ namespace MWClass text += MWGui::ToolTips::getValueString(getValue(ptr), "#{sValue}"); if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { - text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner"); - text += MWGui::ToolTips::getMiscString(ref->mRef.mFaction, "Faction"); + text += MWGui::ToolTips::getMiscString(ptr.getCellRef().getOwner(), "Owner"); + text += MWGui::ToolTips::getMiscString(ptr.getCellRef().getFaction(), "Faction"); text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script"); } diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index e568bf8697..1044fb01d4 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -28,11 +28,11 @@ namespace { bool isGold (const MWWorld::Ptr& ptr) { - return Misc::StringUtils::ciEqual(ptr.getCellRef().mRefID, "gold_001") - || Misc::StringUtils::ciEqual(ptr.getCellRef().mRefID, "gold_005") - || Misc::StringUtils::ciEqual(ptr.getCellRef().mRefID, "gold_010") - || Misc::StringUtils::ciEqual(ptr.getCellRef().mRefID, "gold_025") - || Misc::StringUtils::ciEqual(ptr.getCellRef().mRefID, "gold_100"); + return Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_001") + || Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_005") + || Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_010") + || Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_025") + || Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_100"); } } @@ -94,12 +94,12 @@ namespace MWClass ptr.get(); int value = ref->mBase->mData.mValue; - if (ptr.getCellRef().mGoldValue > 1 && ptr.getRefData().getCount() == 1) - value = ptr.getCellRef().mGoldValue; + if (ptr.getCellRef().getGoldValue() > 1 && ptr.getRefData().getCount() == 1) + value = ptr.getCellRef().getGoldValue(); - if (ptr.getCellRef().mSoul != "") + if (ptr.getCellRef().getSoul() != "") { - const ESM::Creature *creature = MWBase::Environment::get().getWorld()->getStore().get().find(ref->mRef.mSoul); + const ESM::Creature *creature = MWBase::Environment::get().getWorld()->getStore().get().find(ref->mRef.getSoul()); value *= creature->mData.mSoul; } @@ -167,9 +167,9 @@ namespace MWClass info.caption = ref->mBase->mName + countString; info.icon = ref->mBase->mIcon; - if (ref->mRef.mSoul != "") + if (ref->mRef.getSoul() != "") { - const ESM::Creature *creature = store.get().find(ref->mRef.mSoul); + const ESM::Creature *creature = store.get().find(ref->mRef.getSoul()); info.caption += " (" + creature->mName + ")"; } @@ -182,8 +182,8 @@ namespace MWClass } if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { - text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner"); - text += MWGui::ToolTips::getMiscString(ref->mRef.mFaction, "Faction"); + text += MWGui::ToolTips::getMiscString(ptr.getCellRef().getOwner(), "Owner"); + text += MWGui::ToolTips::getMiscString(ptr.getCellRef().getFaction(), "Faction"); text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script"); } @@ -219,7 +219,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = newRef.getPtr().get(); newPtr = MWWorld::Ptr(&cell.get().insert(*ref), &cell); - newPtr.getCellRef().mGoldValue = goldAmount; + newPtr.getCellRef().setGoldValue(goldAmount); newPtr.getRefData().setCount(1); } else { MWWorld::LiveCellRef *ref = @@ -231,7 +231,7 @@ namespace MWClass boost::shared_ptr Miscellaneous::use (const MWWorld::Ptr& ptr) const { - if (ptr.getCellRef().mSoul == "") + if (ptr.getCellRef().getSoul().empty()) return boost::shared_ptr(new MWWorld::NullAction()); else return boost::shared_ptr(new MWWorld::ActionSoulgem(ptr)); @@ -242,12 +242,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = item.get(); - return !ref->mBase->mData.mIsKey && (npcServices & ESM::NPC::Misc) - && !Misc::StringUtils::ciEqual(item.getCellRef().mRefID, "gold_001") - && !Misc::StringUtils::ciEqual(item.getCellRef().mRefID, "gold_005") - && !Misc::StringUtils::ciEqual(item.getCellRef().mRefID, "gold_010") - && !Misc::StringUtils::ciEqual(item.getCellRef().mRefID, "gold_025") - && !Misc::StringUtils::ciEqual(item.getCellRef().mRefID, "gold_100"); + return !ref->mBase->mData.mIsKey && (npcServices & ESM::NPC::Misc) && !isGold(item); } float Miscellaneous::getWeight(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index bca7708eab..7405292b4b 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -526,20 +526,24 @@ namespace MWClass (stats.getAttribute(ESM::Attribute::Strength).getModified() * fDamageStrengthMult->getFloat() * 0.1); if(weaphashealth) { - int weapmaxhealth = weapon.get()->mBase->mData.mHealth; - if(weapon.getCellRef().mCharge == -1) - weapon.getCellRef().mCharge = weapmaxhealth; - damage *= float(weapon.getCellRef().mCharge) / weapmaxhealth; + int weapmaxhealth = weapon.getClass().getItemMaxHealth(weapon); + int weaphealth = weapon.getClass().getItemHealth(weapon); + + damage *= float(weaphealth) / weapmaxhealth; + + if (!MWBase::Environment::get().getWorld()->getGodModeState()) + { + // Reduce weapon charge by at least one, but cap at 0 + weaphealth -= std::min(std::max(1, + (int)(damage * gmst.find("fWeaponDamageMult")->getFloat())), weaphealth); + + weapon.getCellRef().setCharge(weaphealth); + } + + // Weapon broken? unequip it + if (weaphealth == 0) + weapon = *inv.unequipItem(weapon, ptr); } - - if (!MWBase::Environment::get().getWorld()->getGodModeState()) - weapon.getCellRef().mCharge -= std::min(std::max(1, - (int)(damage * gmst.find("fWeaponDamageMult")->getFloat())), weapon.getCellRef().mCharge); - - // Weapon broken? unequip it - if (weapon.getCellRef().mCharge == 0) - weapon = *inv.unequipItem(weapon, ptr); - } healthdmg = true; } @@ -705,14 +709,13 @@ namespace MWClass MWWorld::Ptr armor = ((armorslot != inv.end()) ? *armorslot : MWWorld::Ptr()); if(!armor.isEmpty() && armor.getTypeName() == typeid(ESM::Armor).name()) { - ESM::CellRef &armorref = armor.getCellRef(); - if(armorref.mCharge == -1) - armorref.mCharge = armor.get()->mBase->mData.mHealth; - armorref.mCharge -= std::min(std::max(1, (int)damagediff), - armorref.mCharge); + int armorhealth = armor.getClass().getItemHealth(armor); + armorhealth -= std::min(std::max(1, (int)damagediff), + armorhealth); + armor.getCellRef().setCharge(armorhealth); // Armor broken? unequip it - if (armorref.mCharge == 0) + if (armorhealth == 0) inv.unequipItem(armor, ptr); if (ptr.getRefData().getHandle() == "player") @@ -1316,14 +1319,14 @@ namespace MWClass { // Note we do not respawn moved references in the cell they were moved to. Instead they are respawned in the original cell. // This also means we cannot respawn dynamically placed references with no content file connection. - if (ptr.getCellRef().mRefNum.mContentFile != -1) + if (ptr.getCellRef().getRefNum().mContentFile != -1) { if (ptr.getRefData().getCount() == 0) ptr.getRefData().setCount(1); // Reset to original position ESM::Position& pos = ptr.getRefData().getPosition(); - pos = ptr.getCellRef().mPos; + pos = ptr.getCellRef().getPosition(); ptr.getRefData().setCustomData(NULL); } @@ -1335,7 +1338,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); const ESM::InventoryList& list = ref->mBase->mInventory; MWWorld::ContainerStore& store = getContainerStore(ptr); - store.restock(list, ptr, ptr.getCellRef().mRefID, ptr.getCellRef().mFaction); + store.restock(list, ptr, ptr.getCellRef().getRefId(), ptr.getCellRef().getFaction()); } const ESM::GameSetting *Npc::fMinWalkSpeed; diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index f9d7947a66..7440617c25 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -151,8 +151,8 @@ namespace MWClass info.isPotion = true; if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { - text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner"); - text += MWGui::ToolTips::getMiscString(ref->mRef.mFaction, "Faction"); + text += MWGui::ToolTips::getMiscString(ptr.getCellRef().getOwner(), "Owner"); + text += MWGui::ToolTips::getMiscString(ptr.getCellRef().getFaction(), "Faction"); text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script"); } diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index d376270cb3..5d076a3c5e 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -85,10 +85,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - if (ptr.getCellRef().mCharge == -1) - return ref->mBase->mData.mValue; - else - return ref->mBase->mData.mValue * (static_cast(ptr.getCellRef().mCharge) / getItemMaxHealth(ptr)); + return ref->mBase->mData.mValue * (static_cast(getItemHealth(ptr)) / getItemMaxHealth(ptr)); } void Probe::registerSelf() @@ -135,7 +132,7 @@ namespace MWClass std::string text; - int remainingUses = (ptr.getCellRef().mCharge != -1) ? ptr.getCellRef().mCharge : ref->mBase->mData.mUses; + int remainingUses = getItemHealth(ptr); text += "\n#{sUses}: " + MWGui::ToolTips::toString(remainingUses); text += "\n#{sQuality}: " + MWGui::ToolTips::toString(ref->mBase->mData.mQuality); @@ -143,8 +140,8 @@ namespace MWClass text += MWGui::ToolTips::getValueString(getValue(ptr), "#{sValue}"); if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { - text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner"); - text += MWGui::ToolTips::getMiscString(ref->mRef.mFaction, "Faction"); + text += MWGui::ToolTips::getMiscString(ptr.getCellRef().getOwner(), "Owner"); + text += MWGui::ToolTips::getMiscString(ptr.getCellRef().getFaction(), "Faction"); text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script"); } diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index af79a96915..9b528a4fce 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -76,10 +76,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - if (ptr.getCellRef().mCharge == -1) - return ref->mBase->mData.mValue; - else - return ref->mBase->mData.mValue * (static_cast(ptr.getCellRef().mCharge) / getItemMaxHealth(ptr)); + return ref->mBase->mData.mValue * (static_cast(getItemHealth(ptr)) / getItemMaxHealth(ptr)); } void Repair::registerSelf() @@ -139,7 +136,7 @@ namespace MWClass std::string text; - int remainingUses = (ptr.getCellRef().mCharge != -1) ? ptr.getCellRef().mCharge : ref->mBase->mData.mUses; + int remainingUses = getItemHealth(ptr); text += "\n#{sUses}: " + MWGui::ToolTips::toString(remainingUses); text += "\n#{sQuality}: " + MWGui::ToolTips::toString(ref->mBase->mData.mQuality); @@ -147,8 +144,8 @@ namespace MWClass text += MWGui::ToolTips::getValueString(getValue(ptr), "#{sValue}"); if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { - text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner"); - text += MWGui::ToolTips::getMiscString(ref->mRef.mFaction, "Faction"); + text += MWGui::ToolTips::getMiscString(ptr.getCellRef().getOwner(), "Owner"); + text += MWGui::ToolTips::getMiscString(ptr.getCellRef().getFaction(), "Faction"); text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script"); } diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index 5edf22b008..26618c021c 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -154,10 +154,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - if (ptr.getCellRef().mCharge == -1) - return ref->mBase->mData.mValue; - else - return ref->mBase->mData.mValue * (static_cast(ptr.getCellRef().mCharge) / getItemMaxHealth(ptr)); + return ref->mBase->mData.mValue * (static_cast(getItemHealth(ptr)) / getItemMaxHealth(ptr)); } void Weapon::registerSelf() @@ -340,7 +337,7 @@ namespace MWClass if (ref->mBase->mData.mType < 11) // thrown weapons and arrows/bolts don't have health, only quantity { - int remainingHealth = (ptr.getCellRef().mCharge != -1) ? ptr.getCellRef().mCharge : ref->mBase->mData.mHealth; + int remainingHealth = getItemHealth(ptr); text += "\n#{sCondition}: " + MWGui::ToolTips::toString(remainingHealth) + "/" + MWGui::ToolTips::toString(ref->mBase->mData.mHealth); } @@ -351,11 +348,11 @@ namespace MWClass info.enchant = ref->mBase->mEnchant; if (!info.enchant.empty()) - info.remainingEnchantCharge = ptr.getCellRef().mEnchantmentCharge; + info.remainingEnchantCharge = ptr.getCellRef().getEnchantmentCharge(); if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { - text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner"); - text += MWGui::ToolTips::getMiscString(ref->mRef.mFaction, "Faction"); + text += MWGui::ToolTips::getMiscString(ptr.getCellRef().getOwner(), "Owner"); + text += MWGui::ToolTips::getMiscString(ptr.getCellRef().getFaction(), "Faction"); text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script"); } @@ -388,7 +385,7 @@ namespace MWClass std::pair Weapon::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const { - if (ptr.getCellRef().mCharge == 0) + if (ptr.getCellRef().getCharge() == 0) return std::make_pair(0, "#{sInventoryMessage1}"); std::pair, bool> slots_ = ptr.getClass().getEquipmentSlots(ptr); diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp index 237d145a2e..811f93b486 100644 --- a/apps/openmw/mwgui/console.cpp +++ b/apps/openmw/mwgui/console.cpp @@ -413,7 +413,7 @@ namespace MWGui } else { - setTitle("#{sConsoleTitle} (" + object.getCellRef().mRefID + ")"); + setTitle("#{sConsoleTitle} (" + object.getCellRef().getRefId() + ")"); mPtr = object; } // User clicked on an object. Restore focus to the console command line. diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index b303848df5..29fe6f82d5 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -306,7 +306,7 @@ namespace MWGui for (int i=0; i<2; ++i) { MWWorld::Ptr item = (i == 0) ? mEnchanting.getOldItem() : mEnchanting.getGem(); - if (Misc::StringUtils::ciEqual(item.getCellRef().mOwner, mPtr.getCellRef().mRefID)) + if (Misc::StringUtils::ciEqual(item.getCellRef().getOwner(), mPtr.getCellRef().getRefId())) { std::string msg = MWBase::Environment::get().getWorld()->getStore().get().find("sNotifyMessage49")->getString(); if (msg.find("%s") != std::string::npos) diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 103c48ca14..ede5750a56 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -40,7 +40,7 @@ namespace MWGui else dropped = world->dropObjectOnGround(world->getPlayerPtr(), item.mBase, count); if (setNewOwner) - dropped.getCellRef().mOwner = ""; + dropped.getCellRef().setOwner(""); return dropped; } diff --git a/apps/openmw/mwgui/inventoryitemmodel.cpp b/apps/openmw/mwgui/inventoryitemmodel.cpp index e1bc9d4daa..ad1a4e9537 100644 --- a/apps/openmw/mwgui/inventoryitemmodel.cpp +++ b/apps/openmw/mwgui/inventoryitemmodel.cpp @@ -67,7 +67,7 @@ MWWorld::Ptr InventoryItemModel::moveItem(const ItemStack &item, size_t count, I if (mActor.getClass().isActor() && mActor.getClass().getCreatureStats(mActor).isDead() // Make sure that the item is actually owned by the dead actor // Prevents a potential exploit for resetting the owner of any item, by placing the item in a corpse - && Misc::StringUtils::ciEqual(item.mBase.getCellRef().mOwner, mActor.getCellRef().mRefID)) + && Misc::StringUtils::ciEqual(item.mBase.getCellRef().getOwner(), mActor.getCellRef().getRefId())) setNewOwner = true; MWWorld::Ptr ret = otherModel->copyItem(item, count, setNewOwner); @@ -87,7 +87,7 @@ void InventoryItemModel::update() // NOTE: Don't show WerewolfRobe objects in the inventory, or allow them to be taken. // Vanilla likely uses a hack like this since there's no other way to prevent it from // being shown or taken. - if(item.getCellRef().mRefID == "werewolfrobe") + if(item.getCellRef().getRefId() == "werewolfrobe") continue; ItemStack newItem (item, this, item.getRefData().getCount()); diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 788f90f504..b1e8052d8c 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -168,8 +168,8 @@ namespace MWGui int count = item.mCount; // Bound items may not be moved - if (item.mBase.getCellRef().mRefID.size() > 6 - && item.mBase.getCellRef().mRefID.substr(0,6) == "bound_") + if (item.mBase.getCellRef().getRefId().size() > 6 + && item.mBase.getCellRef().getRefId().substr(0,6) == "bound_") { MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); MWBase::Environment::get().getWindowManager()->messageBox("#{sBarterDialog12}"); @@ -454,7 +454,7 @@ namespace MWGui // NOTE: Don't allow users to select WerewolfRobe objects in the inventory. Vanilla // likely uses a hack like this since there's no other way to prevent it from being // taken. - if(item.getCellRef().mRefID == "werewolfrobe") + if(item.getCellRef().getRefId() == "werewolfrobe") return MWWorld::Ptr(); return item; } diff --git a/apps/openmw/mwgui/merchantrepair.cpp b/apps/openmw/mwgui/merchantrepair.cpp index 83527a8845..50e7644fb9 100644 --- a/apps/openmw/mwgui/merchantrepair.cpp +++ b/apps/openmw/mwgui/merchantrepair.cpp @@ -47,7 +47,7 @@ void MerchantRepair::startRepair(const MWWorld::Ptr &actor) if (iter->getClass().hasItemHealth(*iter)) { int maxDurability = iter->getClass().getItemMaxHealth(*iter); - int durability = (iter->getCellRef().mCharge == -1) ? maxDurability : iter->getCellRef().mCharge; + int durability = iter->getClass().getItemHealth(*iter); if (maxDurability == durability) continue; @@ -114,7 +114,7 @@ void MerchantRepair::onRepairButtonClick(MyGUI::Widget *sender) { // repair MWWorld::Ptr item = *sender->getUserData(); - item.getCellRef().mCharge = item.getClass().getItemMaxHealth(item); + item.getCellRef().setCharge(item.getClass().getItemMaxHealth(item)); MWBase::Environment::get().getSoundManager()->playSound("Repair",1,1); diff --git a/apps/openmw/mwgui/pickpocketitemmodel.cpp b/apps/openmw/mwgui/pickpocketitemmodel.cpp index 0196bf02d3..230282f152 100644 --- a/apps/openmw/mwgui/pickpocketitemmodel.cpp +++ b/apps/openmw/mwgui/pickpocketitemmodel.cpp @@ -42,8 +42,8 @@ namespace MWGui const ItemStack& item = mSourceModel->getItem(i); // Bound items may not be stolen - if (item.mBase.getCellRef().mRefID.size() > 6 - && item.mBase.getCellRef().mRefID.substr(0,6) == "bound_") + if (item.mBase.getCellRef().getRefId().size() > 6 + && item.mBase.getCellRef().getRefId().substr(0,6) == "bound_") { continue; } diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index 5df2b12b8d..90abbb1450 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -274,11 +274,11 @@ namespace MWGui if (item.getRefData ().getCount() < 1) { // Try searching for a compatible replacement - std::string id = item.getCellRef().mRefID; + std::string id = item.getCellRef().getRefId(); for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it) { - if (Misc::StringUtils::ciEqual(it->getCellRef().mRefID, id)) + if (Misc::StringUtils::ciEqual(it->getCellRef().getRefId(), id)) { item = *it; button->getChildAt(0)->setUserData(item); @@ -408,7 +408,7 @@ namespace MWGui case Type_MagicItem: { MWWorld::Ptr item = *button->getChildAt(0)->getUserData(); - key.mId = item.getCellRef().mRefID; + key.mId = item.getCellRef().getRefId(); break; } case Type_Magic: @@ -458,11 +458,12 @@ namespace MWGui MWWorld::Ptr item; for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it) { - if (Misc::StringUtils::ciEqual(it->getCellRef().mRefID, id)) + if (Misc::StringUtils::ciEqual(it->getCellRef().getRefId(), id)) { if (item.isEmpty() || // Prefer the stack with the lowest remaining uses - (it->getCellRef().mCharge != -1 && (item.getCellRef().mCharge == -1 || it->getCellRef().mCharge < item.getCellRef().mCharge) )) + !item.getClass().hasItemHealth(*it) || + it->getClass().getItemHealth(*it) < item.getClass().getItemHealth(item)) { item = *it; } diff --git a/apps/openmw/mwgui/recharge.cpp b/apps/openmw/mwgui/recharge.cpp index 313650bb64..5c4f3eb5a5 100644 --- a/apps/openmw/mwgui/recharge.cpp +++ b/apps/openmw/mwgui/recharge.cpp @@ -56,7 +56,7 @@ void Recharge::updateView() { MWWorld::Ptr gem = *mGemIcon->getUserData(); - std::string soul = gem.getCellRef().mSoul; + std::string soul = gem.getCellRef().getSoul(); const ESM::Creature *creature = MWBase::Environment::get().getWorld()->getStore().get().find(soul); mChargeLabel->setCaptionWithReplacing("#{sCharges} " + boost::lexical_cast(creature->mData.mSoul)); @@ -93,8 +93,8 @@ void Recharge::updateView() if (enchantmentName.empty()) continue; const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get().find(enchantmentName); - if (iter->getCellRef().mEnchantmentCharge >= enchantment->mData.mCharge - || iter->getCellRef().mEnchantmentCharge == -1) + if (iter->getCellRef().getEnchantmentCharge() >= enchantment->mData.mCharge + || iter->getCellRef().getEnchantmentCharge() == -1) continue; MyGUI::TextBox* text = mView->createWidget ( @@ -118,7 +118,7 @@ void Recharge::updateView() Widgets::MWDynamicStatPtr chargeWidget = mView->createWidget ("MW_ChargeBar", MyGUI::IntCoord(72, currentY+2, 199, 20), MyGUI::Align::Default); - chargeWidget->setValue(iter->getCellRef().mEnchantmentCharge, enchantment->mData.mCharge); + chargeWidget->setValue(iter->getCellRef().getEnchantmentCharge(), enchantment->mData.mCharge); chargeWidget->setNeedMouseFocus(false); currentY += 32 + 4; @@ -159,15 +159,15 @@ void Recharge::onItemClicked(MyGUI::Widget *sender) int roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 100; // [0, 99] if (roll < x) { - std::string soul = gem.getCellRef().mSoul; + std::string soul = gem.getCellRef().getSoul(); const ESM::Creature *creature = MWBase::Environment::get().getWorld()->getStore().get().find(soul); float restored = creature->mData.mSoul * (roll / x); const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get().find( item.getClass().getEnchantment(item)); - item.getCellRef().mEnchantmentCharge = - std::min(item.getCellRef().mEnchantmentCharge + restored, static_cast(enchantment->mData.mCharge)); + item.getCellRef().setEnchantmentCharge( + std::min(item.getCellRef().getEnchantmentCharge() + restored, static_cast(enchantment->mData.mCharge))); player.getClass().skillUsageSucceeded (player, ESM::Skill::Enchant, 0); } diff --git a/apps/openmw/mwgui/repair.cpp b/apps/openmw/mwgui/repair.cpp index a3df2dfbea..1ae02599ee 100644 --- a/apps/openmw/mwgui/repair.cpp +++ b/apps/openmw/mwgui/repair.cpp @@ -56,7 +56,7 @@ void Repair::updateRepairView() MWWorld::LiveCellRef *ref = mRepair.getTool().get(); - int uses = (mRepair.getTool().getCellRef().mCharge != -1) ? mRepair.getTool().getCellRef().mCharge : ref->mBase->mData.mUses; + int uses = mRepair.getTool().getClass().getItemHealth(mRepair.getTool()); float quality = ref->mBase->mData.mQuality; @@ -98,7 +98,7 @@ void Repair::updateRepairView() if (iter->getClass().hasItemHealth(*iter)) { int maxDurability = iter->getClass().getItemMaxHealth(*iter); - int durability = (iter->getCellRef().mCharge == -1) ? maxDurability : iter->getCellRef().mCharge; + int durability = iter->getClass().getItemHealth(*iter); if (maxDurability == durability) continue; diff --git a/apps/openmw/mwgui/sortfilteritemmodel.cpp b/apps/openmw/mwgui/sortfilteritemmodel.cpp index 475f73a072..b8dcbcbbb1 100644 --- a/apps/openmw/mwgui/sortfilteritemmodel.cpp +++ b/apps/openmw/mwgui/sortfilteritemmodel.cpp @@ -114,7 +114,7 @@ namespace MWGui if ((mFilter & Filter_OnlyEnchanted) && !(item.mFlags & ItemStack::Flag_Enchanted)) return false; if ((mFilter & Filter_OnlyChargedSoulstones) && (base.getTypeName() != typeid(ESM::Miscellaneous).name() - || base.getCellRef().mSoul == "")) + || base.getCellRef().getSoul() == "")) return false; if ((mFilter & Filter_OnlyEnchantable) && (item.mFlags & ItemStack::Flag_Enchanted || (base.getTypeName() != typeid(ESM::Armor).name() diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index 16e4741432..fb5a80cc7d 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -238,7 +238,7 @@ namespace MWGui int castCost = std::max(1.f, enchantCost - (enchantCost / 100) * (eSkill - 10)); std::string cost = boost::lexical_cast(castCost); - int currentCharge = int(item.getCellRef().mEnchantmentCharge); + int currentCharge = int(item.getCellRef().getEnchantmentCharge()); if (currentCharge == -1) currentCharge = enchant->mData.mCharge; std::string charge = boost::lexical_cast(currentCharge); diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index dd29f40ce4..aeb79a9381 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -97,7 +97,7 @@ namespace MWGui setCoord(0, 0, 300, 300); mDynamicToolTipBox->setVisible(true); ToolTipInfo info; - info.caption=mFocusObject.getCellRef().mRefID; + info.caption=mFocusObject.getCellRef().getRefId(); info.icon=""; tooltipSize = createToolTip(info); } diff --git a/apps/openmw/mwgui/tradeitemmodel.cpp b/apps/openmw/mwgui/tradeitemmodel.cpp index 18b0d5ae3f..fe43eb5483 100644 --- a/apps/openmw/mwgui/tradeitemmodel.cpp +++ b/apps/openmw/mwgui/tradeitemmodel.cpp @@ -148,14 +148,14 @@ namespace MWGui if(!mMerchant.isEmpty()) { MWWorld::Ptr base = item.mBase; - if(Misc::StringUtils::ciEqual(base.getCellRef().mRefID, MWWorld::ContainerStore::sGoldId)) + if(Misc::StringUtils::ciEqual(base.getCellRef().getRefId(), MWWorld::ContainerStore::sGoldId)) continue; if(!base.getClass().canSell(base, services)) continue; // Bound items may not be bought - if (item.mBase.getCellRef().mRefID.size() > 6 - && item.mBase.getCellRef().mRefID.substr(0,6) == "bound_") + if (item.mBase.getCellRef().getRefId().size() > 6 + && item.mBase.getCellRef().getRefId().substr(0,6) == "bound_") { continue; } diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 4baa48e7cf..558e955f0d 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -277,7 +277,7 @@ namespace MWGui // check if the player is attempting to sell back an item stolen from this actor for (std::vector::iterator it = merchantBought.begin(); it != merchantBought.end(); ++it) { - if (Misc::StringUtils::ciEqual(it->mBase.getCellRef().mOwner, mPtr.getCellRef().mRefID)) + if (Misc::StringUtils::ciEqual(it->mBase.getCellRef().getOwner(), mPtr.getCellRef().getRefId())) { std::string msg = gmst.find("sNotifyMessage49")->getString(); if (msg.find("%s") != std::string::npos) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 40fcc35300..a42dca79e5 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1029,16 +1029,16 @@ namespace MWGui const ESM::Enchantment* ench = MWBase::Environment::get().getWorld()->getStore().get() .find(item.getClass().getEnchantment(item)); - int chargePercent = (item.getCellRef().mEnchantmentCharge == -1) ? 100 - : (item.getCellRef().mEnchantmentCharge / static_cast(ench->mData.mCharge) * 100); + int chargePercent = (item.getCellRef().getEnchantmentCharge() == -1) ? 100 + : (item.getCellRef().getEnchantmentCharge() / static_cast(ench->mData.mCharge) * 100); mHud->setSelectedEnchantItem(item, chargePercent); mSpellWindow->setTitle(item.getClass().getName(item)); } void WindowManager::setSelectedWeapon(const MWWorld::Ptr& item) { - int durabilityPercent = (item.getCellRef().mCharge == -1) ? 100 - : (item.getCellRef().mCharge / static_cast(item.getClass().getItemMaxHealth(item)) * 100); + int durabilityPercent = + (item.getClass().getItemHealth(item) / static_cast(item.getClass().getItemMaxHealth(item)) * 100); mHud->setSelectedWeapon(item, durabilityPercent); mInventoryWindow->setTitle(item.getClass().getName(item)); } diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 35667a23c4..9f141a951b 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -62,17 +62,17 @@ bool disintegrateSlot (MWWorld::Ptr ptr, int slot, float disintegrate) { if (!item->getClass().hasItemHealth(*item)) return false; - if (item->getCellRef().mCharge == -1) - item->getCellRef().mCharge = item->getClass().getItemMaxHealth(*item); + int charge = item->getClass().getItemHealth(*item); - if (item->getCellRef().mCharge == 0) + if (charge == 0) return false; - item->getCellRef().mCharge -= + charge -= std::min(disintegrate, - static_cast(item->getCellRef().mCharge)); + static_cast(charge)); + item->getCellRef().setCharge(charge); - if (item->getCellRef().mCharge == 0) + if (charge == 0) { // Will unequip the broken item and try to find a replacement if (ptr.getRefData().getHandle() != "player") @@ -147,13 +147,13 @@ namespace MWMechanics for (MWWorld::ContainerStoreIterator it = container.begin(MWWorld::ContainerStore::Type_Miscellaneous); it != container.end(); ++it) { - const std::string& id = it->getCellRef().mRefID; + const std::string& id = it->getCellRef().getRefId(); if (id.size() >= soulgemFilter.size() && id.substr(0,soulgemFilter.size()) == soulgemFilter) { float thisGemCapacity = it->get()->mBase->mData.mValue * fSoulgemMult; if (thisGemCapacity >= creatureSoulValue && thisGemCapacity < gemCapacity - && it->getCellRef().mSoul.empty()) + && it->getCellRef().getSoul().empty()) { gem = it; gemCapacity = thisGemCapacity; @@ -166,7 +166,7 @@ namespace MWMechanics // Set the soul on just one of the gems, not the whole stack gem->getContainerStore()->unstack(*gem, caster); - gem->getCellRef().mSoul = mCreature.getCellRef().mRefID; + gem->getCellRef().setSoul(mCreature.getCellRef().getRefId()); if (caster.getRefData().getHandle() == "player") MWBase::Environment::get().getWindowManager()->messageBox("#{sSoultrapSuccess}"); @@ -546,7 +546,7 @@ namespace MWMechanics { MWWorld::CellStore* store = ptr.getCell(); MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), creatureID, 1); - ref.getPtr().getCellRef().mPos = ipos; + ref.getPtr().getCellRef().setPosition(ipos); MWMechanics::CreatureStats& summonedCreatureStats = ref.getPtr().getClass().getCreatureStats(ref.getPtr()); @@ -1142,7 +1142,7 @@ namespace MWMechanics if(!stats.isDead() && stats.getAiSequence().getTypeId() == AiPackage::TypeIdFollow) { MWMechanics::AiFollow* package = static_cast(stats.getAiSequence().getActivePackage()); - if(package->getFollowedActor() == actor.getCellRef().mRefID) + if(package->getFollowedActor() == actor.getCellRef().getRefId()) list.push_front(iter->first); } } diff --git a/apps/openmw/mwmechanics/aiavoiddoor.cpp b/apps/openmw/mwmechanics/aiavoiddoor.cpp index 5045225828..ea6f296cc8 100644 --- a/apps/openmw/mwmechanics/aiavoiddoor.cpp +++ b/apps/openmw/mwmechanics/aiavoiddoor.cpp @@ -73,11 +73,6 @@ bool MWMechanics::AiAvoidDoor::execute (const MWWorld::Ptr& actor,float duration return false; } -std::string MWMechanics::AiAvoidDoor::getAvoidedDoor() -{ - return mDoorPtr.getCellRef().mRefID; -} - MWMechanics::AiAvoidDoor *MWMechanics::AiAvoidDoor::clone() const { return new AiAvoidDoor(*this); diff --git a/apps/openmw/mwmechanics/aiavoiddoor.hpp b/apps/openmw/mwmechanics/aiavoiddoor.hpp index c1b3261981..d2a2e33a1f 100644 --- a/apps/openmw/mwmechanics/aiavoiddoor.hpp +++ b/apps/openmw/mwmechanics/aiavoiddoor.hpp @@ -24,9 +24,6 @@ namespace MWMechanics virtual int getTypeId() const; - /// Returns the door being avoided - std::string getAvoidedDoor(); - private: float mDuration; MWWorld::Ptr mDoorPtr; diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 1027cc48a7..8ea9be3399 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -517,7 +517,7 @@ namespace MWMechanics { MWWorld::LiveCellRef& ref = *mDoorIter; float minSqr = 1.3*1.3*MIN_DIST_TO_DOOR_SQUARED; // for legibility - if(vActorPos.squaredDistance(Ogre::Vector3(ref.mRef.mPos.pos)) < minSqr && + if(vActorPos.squaredDistance(Ogre::Vector3(ref.mRef.getPosition().pos)) < minSqr && ref.mData.getLocalRotation().rot[2] < 0.4f) // even small opening { //std::cout<<"closed door id \""<execute(actor); mLastDoorChecked = door; } diff --git a/apps/openmw/mwmechanics/combat.cpp b/apps/openmw/mwmechanics/combat.cpp index 5ffa7a547f..69c3c08f76 100644 --- a/apps/openmw/mwmechanics/combat.cpp +++ b/apps/openmw/mwmechanics/combat.cpp @@ -102,10 +102,11 @@ namespace MWMechanics if (roll < x) { // Reduce shield durability by incoming damage - if (shield->getCellRef().mCharge == -1) - shield->getCellRef().mCharge = shield->getClass().getItemMaxHealth(*shield); - shield->getCellRef().mCharge -= std::min(shield->getCellRef().mCharge, int(damage)); - if (!shield->getCellRef().mCharge) + int shieldhealth = shield->getClass().getItemHealth(*shield); + + shieldhealth -= std::min(shieldhealth, int(damage)); + shield->getCellRef().setCharge(shieldhealth); + if (shieldhealth == 0) inv.unequipItem(*shield, blocker); // Reduce blocker fatigue diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index 9c5c9dbb9d..f3f6795db8 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -234,9 +234,9 @@ namespace MWMechanics const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); if(soulEmpty()) return 0; - if(mSoulGemPtr.getCellRef().mSoul=="") + if(mSoulGemPtr.getCellRef().getSoul()=="") return 0; - const ESM::Creature* soul = store.get().find(mSoulGemPtr.getCellRef().mSoul); + const ESM::Creature* soul = store.get().find(mSoulGemPtr.getCellRef().getSoul()); return soul->mData.mSoul; } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index d25be1e13f..0d5bae42bd 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -24,10 +24,10 @@ namespace /// @return is \a ptr allowed to take/use \a item or is it a crime? bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, MWWorld::Ptr& victim) { - const std::string& owner = item.getCellRef().mOwner; + const std::string& owner = item.getCellRef().getOwner(); bool isOwned = !owner.empty() && owner != "player"; - const std::string& faction = item.getCellRef().mFaction; + const std::string& faction = item.getCellRef().getFaction(); bool isFactionOwned = false; if (!faction.empty() && ptr.getClass().isNpc()) { @@ -36,8 +36,8 @@ namespace isFactionOwned = true; } - if (!item.getCellRef().mOwner.empty()) - victim = MWBase::Environment::get().getWorld()->searchPtr(item.getCellRef().mOwner, true); + if (!item.getCellRef().getOwner().empty()) + victim = MWBase::Environment::get().getWorld()->searchPtr(item.getCellRef().getOwner(), true); return (!isOwned && !isFactionOwned); } diff --git a/apps/openmw/mwmechanics/obstacle.cpp b/apps/openmw/mwmechanics/obstacle.cpp index fc781e6377..55ebfeab54 100644 --- a/apps/openmw/mwmechanics/obstacle.cpp +++ b/apps/openmw/mwmechanics/obstacle.cpp @@ -50,7 +50,7 @@ namespace MWMechanics for (; it != refList.end(); ++it) { MWWorld::LiveCellRef& ref = *it; - if(pos.squaredDistance(Ogre::Vector3(ref.mRef.mPos.pos)) < minSqr) + if(pos.squaredDistance(Ogre::Vector3(ref.mData.getPosition().pos)) < minSqr) if((closed && ref.mData.getLocalRotation().rot[2] == 0) || (!closed && ref.mData.getLocalRotation().rot[2] >= 1)) { diff --git a/apps/openmw/mwmechanics/repair.cpp b/apps/openmw/mwmechanics/repair.cpp index dc8b567a9b..9f2c851cf8 100644 --- a/apps/openmw/mwmechanics/repair.cpp +++ b/apps/openmw/mwmechanics/repair.cpp @@ -28,8 +28,8 @@ void Repair::repair(const MWWorld::Ptr &itemToRepair) player.getClass().getContainerStore(player).unstack(mTool, player); // reduce number of uses left - int uses = (mTool.getCellRef().mCharge != -1) ? mTool.getCellRef().mCharge : ref->mBase->mData.mUses; - mTool.getCellRef().mCharge = uses-1; + int uses = mTool.getClass().getItemHealth(mTool); + mTool.getCellRef().setCharge(uses-1); MWMechanics::CreatureStats& stats = player.getClass().getCreatureStats(player); MWMechanics::NpcStats& npcStats = player.getClass().getNpcStats(player); @@ -53,9 +53,9 @@ void Repair::repair(const MWWorld::Ptr &itemToRepair) y = std::max(1, y); // repair by 'y' points - itemToRepair.getCellRef().mCharge += y; - itemToRepair.getCellRef().mCharge = std::min(itemToRepair.getCellRef().mCharge, - itemToRepair.getClass().getItemMaxHealth(itemToRepair)); + int charge = itemToRepair.getClass().getItemHealth(itemToRepair); + charge = std::min(charge + y, itemToRepair.getClass().getItemMaxHealth(itemToRepair)); + itemToRepair.getCellRef().setCharge(charge); // set the OnPCRepair variable on the item's script std::string script = itemToRepair.getClass().getScript(itemToRepair); @@ -75,7 +75,7 @@ void Repair::repair(const MWWorld::Ptr &itemToRepair) } // tool used up? - if (mTool.getCellRef().mCharge == 0) + if (mTool.getCellRef().getCharge() == 0) { MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); MWWorld::ContainerStore& store = player.getClass().getContainerStore(player); @@ -91,7 +91,7 @@ void Repair::repair(const MWWorld::Ptr &itemToRepair) for (MWWorld::ContainerStoreIterator iter (store.begin()); iter!=store.end(); ++iter) { - if (Misc::StringUtils::ciEqual(iter->getCellRef().mRefID, mTool.getCellRef().mRefID)) + if (Misc::StringUtils::ciEqual(iter->getCellRef().getRefId(), mTool.getCellRef().getRefId())) { mTool = *iter; break; diff --git a/apps/openmw/mwmechanics/security.cpp b/apps/openmw/mwmechanics/security.cpp index bb2e942238..4a049d60f8 100644 --- a/apps/openmw/mwmechanics/security.cpp +++ b/apps/openmw/mwmechanics/security.cpp @@ -29,10 +29,10 @@ namespace MWMechanics void Security::pickLock(const MWWorld::Ptr &lock, const MWWorld::Ptr &lockpick, std::string& resultMessage, std::string& resultSound) { - if (!(lock.getCellRef().mLockLevel > 0)) //If it's unlocked back out immediately + if (!(lock.getCellRef().getLockLevel() > 0)) //If it's unlocked back out immediately return; - int lockStrength = lock.getCellRef().mLockLevel; + int lockStrength = lock.getCellRef().getLockLevel(); float pickQuality = lockpick.get()->mBase->mData.mQuality; @@ -60,22 +60,22 @@ namespace MWMechanics resultMessage = "#{sLockFail}"; } - if (lockpick.getCellRef().mCharge == -1) - lockpick.getCellRef().mCharge = lockpick.get()->mBase->mData.mUses; - --lockpick.getCellRef().mCharge; - if (!lockpick.getCellRef().mCharge) + int uses = lockpick.getClass().getItemHealth(lockpick); + --uses; + lockpick.getCellRef().setCharge(uses); + if (!uses) lockpick.getContainerStore()->remove(lockpick, 1, mActor); } void Security::probeTrap(const MWWorld::Ptr &trap, const MWWorld::Ptr &probe, std::string& resultMessage, std::string& resultSound) { - if (trap.getCellRef().mTrap == "") + if (trap.getCellRef().getTrap() == "") return; float probeQuality = probe.get()->mBase->mData.mQuality; - const ESM::Spell* trapSpell = MWBase::Environment::get().getWorld()->getStore().get().find(trap.getCellRef().mTrap); + const ESM::Spell* trapSpell = MWBase::Environment::get().getWorld()->getStore().get().find(trap.getCellRef().getTrap()); float trapSpellPoints = trapSpell->mData.mCost; float fTrapCostMult = MWBase::Environment::get().getWorld()->getStore().get().find("fTrapCostMult")->getFloat(); @@ -93,7 +93,7 @@ namespace MWMechanics int roll = static_cast (std::rand()) / RAND_MAX * 100; if (roll <= x) { - trap.getCellRef().mTrap = ""; + trap.getCellRef().setTrap(""); resultSound = "Disarm Trap"; resultMessage = "#{sTrapSuccess}"; @@ -103,10 +103,10 @@ namespace MWMechanics resultMessage = "#{sTrapFail}"; } - if (probe.getCellRef().mCharge == -1) - probe.getCellRef().mCharge = probe.get()->mBase->mData.mUses; - --probe.getCellRef().mCharge; - if (!probe.getCellRef().mCharge) + int uses = probe.getClass().getItemHealth(probe); + --uses; + probe.getCellRef().setCharge(uses); + if (!uses) probe.getContainerStore()->remove(probe, 1, mActor); } diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 91a81c74be..c996e90d6f 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -470,21 +470,21 @@ namespace MWMechanics { if (effectId == ESM::MagicEffect::Lock) { - if (target.getCellRef().mLockLevel < magnitude) //If the door is not already locked to a higher value, lock it to spell magnitude - target.getCellRef().mLockLevel = magnitude; + if (target.getCellRef().getLockLevel() < magnitude) //If the door is not already locked to a higher value, lock it to spell magnitude + target.getCellRef().setLockLevel(magnitude); } else if (effectId == ESM::MagicEffect::Open) { - if (target.getCellRef().mLockLevel <= magnitude) + if (target.getCellRef().getLockLevel() <= magnitude) { - //Door not already unlocked - if (target.getCellRef().mLockLevel > 0) + if (target.getCellRef().getLockLevel() > 0) { + //Door not already unlocked MWBase::Environment::get().getSoundManager()->playSound3D(target, "Open Lock", 1.f, 1.f); if (!caster.isEmpty() && caster.getClass().isActor()) MWBase::Environment::get().getMechanicsManager()->objectOpened(caster, target); } - target.getCellRef().mLockLevel = -abs(target.getCellRef().mLockLevel); //unlocks the door + target.getCellRef().setLockLevel(-abs(target.getCellRef().getLockLevel())); //unlocks the door } else MWBase::Environment::get().getSoundManager()->playSound3D(target, "Open Lock Fail", 1.f, 1.f); @@ -588,7 +588,7 @@ namespace MWMechanics throw std::runtime_error("can't cast an item without an enchantment"); mSourceName = item.getClass().getName(item); - mId = item.getCellRef().mRefID; + mId = item.getCellRef().getRefId(); const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get().find(enchantmentName); @@ -601,10 +601,10 @@ namespace MWMechanics int eSkill = mCaster.getClass().getSkill(mCaster, ESM::Skill::Enchant); const int castCost = std::max(1.f, enchantCost - (enchantCost / 100) * (eSkill - 10)); - if (item.getCellRef().mEnchantmentCharge == -1) - item.getCellRef().mEnchantmentCharge = enchantment->mData.mCharge; + if (item.getCellRef().getEnchantmentCharge() == -1) + item.getCellRef().setEnchantmentCharge(enchantment->mData.mCharge); - if (item.getCellRef().mEnchantmentCharge < castCost) + if (item.getCellRef().getEnchantmentCharge() < castCost) { // TODO: Should there be a sound here? if (mCaster.getRefData().getHandle() == "player") @@ -612,7 +612,7 @@ namespace MWMechanics return false; } // Reduce charge - item.getCellRef().mEnchantmentCharge -= castCost; + item.getCellRef().setEnchantmentCharge(item.getCellRef().getEnchantmentCharge() - castCost); } if (enchantment->mData.mType == ESM::Enchantment::WhenUsed) diff --git a/apps/openmw/mwrender/actors.cpp b/apps/openmw/mwrender/actors.cpp index 820ba8acca..a9c9884d58 100644 --- a/apps/openmw/mwrender/actors.cpp +++ b/apps/openmw/mwrender/actors.cpp @@ -49,10 +49,10 @@ void Actors::insertBegin(const MWWorld::Ptr &ptr) Ogre::SceneNode* insert = cellnode->createChildSceneNode(); const float *f = ptr.getRefData().getPosition().pos; insert->setPosition(f[0], f[1], f[2]); - insert->setScale(ptr.getCellRef().mScale, ptr.getCellRef().mScale, ptr.getCellRef().mScale); + insert->setScale(ptr.getCellRef().getScale(), ptr.getCellRef().getScale(), ptr.getCellRef().getScale()); // Convert MW rotation to a quaternion: - f = ptr.getCellRef().mPos.rot; + f = ptr.getCellRef().getPosition().rot; // Rotate around X axis Ogre::Quaternion xr(Ogre::Radian(-f[0]), Ogre::Vector3::UNIT_X); diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 3b8b91b0e4..9124e89b88 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -290,7 +290,7 @@ void Animation::addAnimSource(const std::string &model) mAccumRoot = mNonAccumRoot->getParent(); if(!mAccumRoot) { - std::cerr<< "Non-Accum root for "<getParent(); if(!mAccumRoot) { - std::cerr<< "Non-Accum root for "<setPosition(f[0], f[1], f[2]); - insert->setScale(ptr.getCellRef().mScale, ptr.getCellRef().mScale, ptr.getCellRef().mScale); + insert->setScale(ptr.getCellRef().getScale(), ptr.getCellRef().getScale(), ptr.getCellRef().getScale()); // Convert MW rotation to a quaternion: - f = ptr.getCellRef().mPos.rot; + f = ptr.getCellRef().getPosition().rot; // Rotate around X axis Ogre::Quaternion xr(Ogre::Radian(-f[0]), Ogre::Vector3::UNIT_X); diff --git a/apps/openmw/mwscript/cellextensions.cpp b/apps/openmw/mwscript/cellextensions.cpp index 825d62efb5..a5bd121526 100644 --- a/apps/openmw/mwscript/cellextensions.cpp +++ b/apps/openmw/mwscript/cellextensions.cpp @@ -88,6 +88,11 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { + if (!MWBase::Environment::get().getWorld()->getPlayerPtr().isInCell()) + { + runtime.push (0); + return; + } bool interior = !MWBase::Environment::get().getWorld()->getPlayerPtr().getCell()->getCell()->isExterior(); diff --git a/apps/openmw/mwscript/containerextensions.cpp b/apps/openmw/mwscript/containerextensions.cpp index 6737d6a945..93711d036e 100644 --- a/apps/openmw/mwscript/containerextensions.cpp +++ b/apps/openmw/mwscript/containerextensions.cpp @@ -121,7 +121,7 @@ namespace MWScript std::string itemName; for (MWWorld::ContainerStoreIterator iter(store.begin()); iter != store.end(); ++iter) - if (::Misc::StringUtils::ciEqual(iter->getCellRef().mRefID, item)) + if (::Misc::StringUtils::ciEqual(iter->getCellRef().getRefId(), item)) itemName = iter->getClass().getName(*iter); int numRemoved = store.remove(item, count, ptr); @@ -165,7 +165,7 @@ namespace MWScript MWWorld::ContainerStoreIterator it = invStore.begin(); for (; it != invStore.end(); ++it) { - if (::Misc::StringUtils::ciEqual(it->getCellRef().mRefID, item)) + if (::Misc::StringUtils::ciEqual(it->getCellRef().getRefId(), item)) break; } if (it == invStore.end()) @@ -268,7 +268,7 @@ namespace MWScript for (int slot = 0; slot < MWWorld::InventoryStore::Slots; ++slot) { MWWorld::ContainerStoreIterator it = invStore.getSlot (slot); - if (it != invStore.end() && ::Misc::StringUtils::ciEqual(it->getCellRef().mRefID, item)) + if (it != invStore.end() && ::Misc::StringUtils::ciEqual(it->getCellRef().getRefId(), item)) { runtime.push(1); return; @@ -295,7 +295,7 @@ namespace MWScript it != invStore.end(); ++it) { - if (::Misc::StringUtils::ciEqual(it->getCellRef().mSoul, name)) + if (::Misc::StringUtils::ciEqual(it->getCellRef().getSoul(), name)) { runtime.push(1); return; diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index b0d73253ff..fa17d96af3 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -131,7 +131,7 @@ namespace MWScript { MWWorld::Ptr ptr = R()(runtime); - Interpreter::Type_Integer lockLevel = ptr.getCellRef().mLockLevel; + Interpreter::Type_Integer lockLevel = ptr.getCellRef().getLockLevel(); if(lockLevel==0) { //no lock level was ever set, set to 100 as default lockLevel = 100; } @@ -324,7 +324,7 @@ namespace MWScript { MWWorld::Ptr ptr = R()(runtime); - runtime.push (ptr.getCellRef().mLockLevel > 0); + runtime.push (ptr.getCellRef().getLockLevel() > 0); } }; @@ -369,7 +369,7 @@ namespace MWScript store.get().find(creature); // This line throws an exception if it can't find the creature MWWorld::Ptr item = *ptr.getClass().getContainerStore(ptr).add(gem, 1, ptr); - item.getCellRef().mSoul = creature; + item.getCellRef().setSoul(creature); } }; @@ -392,7 +392,7 @@ namespace MWScript MWWorld::ContainerStore& store = ptr.getClass().getContainerStore (ptr); for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it) { - if (::Misc::StringUtils::ciEqual(it->getCellRef().mSoul, soul)) + if (::Misc::StringUtils::ciEqual(it->getCellRef().getSoul(), soul)) { store.remove(*it, 1, ptr); return; @@ -430,7 +430,7 @@ namespace MWScript int toRemove = amount; for (MWWorld::ContainerStoreIterator iter (store.begin()); iter!=store.end(); ++iter) { - if (::Misc::StringUtils::ciEqual(iter->getCellRef().mRefID, item)) + if (::Misc::StringUtils::ciEqual(iter->getCellRef().getRefId(), item)) { int removed = store.remove(*iter, toRemove, ptr); MWBase::Environment::get().getWorld()->dropObjectOnGround(ptr, *iter, removed); @@ -462,7 +462,7 @@ namespace MWScript for (MWWorld::ContainerStoreIterator iter (store.begin()); iter!=store.end(); ++iter) { - if (::Misc::StringUtils::ciEqual(iter->getCellRef().mSoul, soul)) + if (::Misc::StringUtils::ciEqual(iter->getCellRef().getSoul(), soul)) { MWBase::Environment::get().getWorld()->dropObjectOnGround(ptr, *iter, 1); store.remove(*iter, 1, ptr); @@ -659,10 +659,10 @@ namespace MWScript const std::string script = ptr.getClass().getScript(ptr); if(script.empty()) - str<< ptr.getCellRef().mRefID<<" ("<getLocals(script); diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index fb27e73f44..a944a31b8d 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -47,7 +47,7 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { MWWorld::Ptr ptr = R()(runtime); - runtime.push(ptr.getCellRef().mScale); + runtime.push(ptr.getCellRef().getScale()); } }; @@ -64,7 +64,7 @@ namespace MWScript runtime.pop(); // add the parameter to the object's scale. - MWBase::Environment::get().getWorld()->scaleObject(ptr,ptr.getCellRef().mScale + scale); + MWBase::Environment::get().getWorld()->scaleObject(ptr,ptr.getCellRef().getScale() + scale); } }; @@ -117,15 +117,15 @@ namespace MWScript if (axis == "x") { - runtime.push(Ogre::Radian(ptr.getCellRef().mPos.rot[0]).valueDegrees()); + runtime.push(Ogre::Radian(ptr.getCellRef().getPosition().rot[0]).valueDegrees()); } else if (axis == "y") { - runtime.push(Ogre::Radian(ptr.getCellRef().mPos.rot[1]).valueDegrees()); + runtime.push(Ogre::Radian(ptr.getCellRef().getPosition().rot[1]).valueDegrees()); } else if (axis == "z") { - runtime.push(Ogre::Radian(ptr.getCellRef().mPos.rot[2]).valueDegrees()); + runtime.push(Ogre::Radian(ptr.getCellRef().getPosition().rot[2]).valueDegrees()); } else throw std::runtime_error ("invalid rotation axis: " + axis); @@ -247,15 +247,15 @@ namespace MWScript if(axis == "x") { - runtime.push(ptr.getCellRef().mPos.pos[0]); + runtime.push(ptr.getCellRef().getPosition().pos[0]); } else if(axis == "y") { - runtime.push(ptr.getCellRef().mPos.pos[1]); + runtime.push(ptr.getCellRef().getPosition().pos[1]); } else if(axis == "z") { - runtime.push(ptr.getCellRef().mPos.pos[2]); + runtime.push(ptr.getCellRef().getPosition().pos[2]); } else throw std::runtime_error ("invalid axis: " + axis); @@ -415,7 +415,7 @@ namespace MWScript pos.rot[0] = pos.rot[1] = 0; pos.rot[2] = zRot; MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(),itemID); - ref.getPtr().getCellRef().mPos = pos; + ref.getPtr().getCellRef().setPosition(pos); MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),store,pos); } else @@ -456,7 +456,7 @@ namespace MWScript pos.rot[0] = pos.rot[1] = 0; pos.rot[2] = zRot; MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(),itemID); - ref.getPtr().getCellRef().mPos = pos; + ref.getPtr().getCellRef().setPosition(pos); MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),store,pos); } else @@ -523,7 +523,7 @@ namespace MWScript // create item MWWorld::CellStore* store = actor.getCell(); MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), itemID, count); - ref.getPtr().getCellRef().mPos = ipos; + ref.getPtr().getCellRef().setPosition(ipos); MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),store,ipos); } @@ -617,8 +617,8 @@ namespace MWScript ptr.getRefData().getLocalRotation().rot[1] = 0; ptr.getRefData().getLocalRotation().rot[2] = 0; MWBase::Environment::get().getWorld()->rotateObject(ptr, 0,0,0,true); - MWBase::Environment::get().getWorld()->moveObject(ptr, ptr.getCellRef().mPos.pos[0], - ptr.getCellRef().mPos.pos[1], ptr.getCellRef().mPos.pos[2]); + MWBase::Environment::get().getWorld()->moveObject(ptr, ptr.getCellRef().getPosition().pos[0], + ptr.getCellRef().getPosition().pos[1], ptr.getCellRef().getPosition().pos[2]); } }; diff --git a/apps/openmw/mwworld/actiontrap.cpp b/apps/openmw/mwworld/actiontrap.cpp index bcefb0181b..1472afc087 100644 --- a/apps/openmw/mwworld/actiontrap.cpp +++ b/apps/openmw/mwworld/actiontrap.cpp @@ -11,7 +11,7 @@ namespace MWWorld cast.mHitPosition = Ogre::Vector3(actor.getRefData().getPosition().pos); cast.cast(mSpellId); - mTrapSource.getCellRef().mTrap = ""; + mTrapSource.getCellRef().setTrap(""); } } diff --git a/apps/openmw/mwworld/cellref.cpp b/apps/openmw/mwworld/cellref.cpp new file mode 100644 index 0000000000..f16d8e3d17 --- /dev/null +++ b/apps/openmw/mwworld/cellref.cpp @@ -0,0 +1,185 @@ +#include "cellref.hpp" + +#include + +namespace MWWorld +{ + + ESM::RefNum CellRef::getRefNum() const + { + return mCellRef.mRefNum; + } + + std::string CellRef::getRefId() const + { + return mCellRef.mRefID; + } + + bool CellRef::getTeleport() const + { + return mCellRef.mTeleport; + } + + ESM::Position CellRef::getDoorDest() const + { + return mCellRef.mDoorDest; + } + + std::string CellRef::getDestCell() const + { + return mCellRef.mDestCell; + } + + float CellRef::getScale() const + { + return mCellRef.mScale; + } + + void CellRef::setScale(float scale) + { + if (scale != mCellRef.mScale) + { + mChanged = true; + mCellRef.mScale = scale; + } + } + + ESM::Position CellRef::getPosition() const + { + return mCellRef.mPos; + } + + void CellRef::setPosition(const ESM::Position &position) + { + mChanged = true; + mCellRef.mPos = position; + } + + float CellRef::getEnchantmentCharge() const + { + return mCellRef.mEnchantmentCharge; + } + + void CellRef::setEnchantmentCharge(float charge) + { + if (charge != mCellRef.mEnchantmentCharge) + { + mChanged = true; + mCellRef.mEnchantmentCharge = charge; + } + } + + int CellRef::getCharge() const + { + return mCellRef.mCharge; + } + + void CellRef::setCharge(int charge) + { + if (charge != mCellRef.mCharge) + { + mChanged = true; + mCellRef.mCharge = charge; + } + } + + std::string CellRef::getOwner() const + { + return mCellRef.mOwner; + } + + void CellRef::setOwner(const std::string &owner) + { + if (owner != mCellRef.mOwner) + { + mChanged = true; + mCellRef.mOwner = owner; + } + } + + std::string CellRef::getSoul() const + { + return mCellRef.mSoul; + } + + void CellRef::setSoul(const std::string &soul) + { + if (soul != mCellRef.mSoul) + { + mChanged = true; + mCellRef.mSoul = soul; + } + } + + std::string CellRef::getFaction() const + { + return mCellRef.mFaction; + } + + void CellRef::setFaction(const std::string &faction) + { + if (faction != mCellRef.mFaction) + { + mChanged = true; + mCellRef.mFaction = faction; + } + } + + int CellRef::getLockLevel() const + { + return mCellRef.mLockLevel; + } + + void CellRef::setLockLevel(int lockLevel) + { + if (lockLevel != mCellRef.mLockLevel) + { + mChanged = true; + mCellRef.mLockLevel = lockLevel; + } + } + + std::string CellRef::getKey() const + { + return mCellRef.mKey; + } + + std::string CellRef::getTrap() const + { + return mCellRef.mTrap; + } + + void CellRef::setTrap(const std::string& trap) + { + if (trap != mCellRef.mTrap) + { + mChanged = true; + mCellRef.mTrap = trap; + } + } + + int CellRef::getGoldValue() const + { + return mCellRef.mGoldValue; + } + + void CellRef::setGoldValue(int value) + { + if (value != mCellRef.mGoldValue) + { + mChanged = true; + mCellRef.mGoldValue = value; + } + } + + void CellRef::writeState(ESM::ObjectState &state) const + { + state.mRef = mCellRef; + } + + bool CellRef::hasChanged() const + { + return mChanged; + } + +} diff --git a/apps/openmw/mwworld/cellref.hpp b/apps/openmw/mwworld/cellref.hpp new file mode 100644 index 0000000000..3b0c2251be --- /dev/null +++ b/apps/openmw/mwworld/cellref.hpp @@ -0,0 +1,99 @@ +#ifndef OPENMW_MWWORLD_CELLREF_H +#define OPENMW_MWWORLD_CELLREF_H + +#include + +namespace ESM +{ + class ObjectState; +} + +namespace MWWorld +{ + + /// \brief Encapsulated variant of ESM::CellRef with change tracking + class CellRef + { + public: + + CellRef (const ESM::CellRef& ref) + : mCellRef(ref) + { + mChanged = false; + } + + // Note: Currently unused for items in containers + ESM::RefNum getRefNum() const; + + // Id of object being referenced + std::string getRefId() const; + + // For doors - true if this door teleports to somewhere else, false + // if it should open through animation. + bool getTeleport() const; + + // Teleport location for the door, if this is a teleporting door. + ESM::Position getDoorDest() const; + + // Destination cell for doors (optional) + std::string getDestCell() const; + + // Scale applied to mesh + float getScale() const; + void setScale(float scale); + + // Position and rotation of this object within the cell + ESM::Position getPosition() const; + void setPosition (const ESM::Position& position); + + // Remaining enchantment charge. This could be -1 if the charge was not touched yet (i.e. full). + float getEnchantmentCharge() const; + + void setEnchantmentCharge(float charge); + + // For weapon or armor, this is the remaining item health. + // For tools (lockpicks, probes, repair hammer) it is the remaining uses. + int getCharge() const; + void setCharge(int charge); + + // The NPC that owns this object (and will get angry if you steal it) + std::string getOwner() const; + void setOwner(const std::string& owner); + + // ID of creature trapped in this soul gem + std::string getSoul() const; + void setSoul(const std::string& soul); + + // The faction that owns this object (and will get angry if + // you take it and are not a faction member) + std::string getFaction() const; + void setFaction (const std::string& faction); + + // Lock level for doors and containers + // Positive for a locked door. 0 for a door that was never locked. + // For an unlocked door, it is set to -(previous locklevel) + int getLockLevel() const; + void setLockLevel(int lockLevel); + // Key and trap ID names, if any + std::string getKey() const; + std::string getTrap() const; + void setTrap(const std::string& trap); + + // This is 5 for Gold_005 references, 100 for Gold_100 and so on. + int getGoldValue() const; + void setGoldValue(int value); + + // Write the content of this CellRef into the given ObjectState + void writeState (ESM::ObjectState& state) const; + + // Has this CellRef changed since it was originally loaded? + bool hasChanged() const; + + private: + bool mChanged; + ESM::CellRef mCellRef; + }; + +} + +#endif diff --git a/apps/openmw/mwworld/cellreflist.hpp b/apps/openmw/mwworld/cellreflist.hpp index 264929bfb5..9c3370f08a 100644 --- a/apps/openmw/mwworld/cellreflist.hpp +++ b/apps/openmw/mwworld/cellreflist.hpp @@ -27,7 +27,7 @@ namespace MWWorld LiveRef *find (const std::string& name) { for (typename List::iterator iter (mList.begin()); iter!=mList.end(); ++iter) - if (iter->mData.getCount() > 0 && iter->mRef.mRefID == name) + if (iter->mData.getCount() > 0 && iter->mRef.getRefId() == name) return &*iter; return 0; diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 04d733e2c4..63cdbfb1a3 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -72,8 +72,16 @@ namespace iter (collection.mList.begin()); iter!=collection.mList.end(); ++iter) { - if (iter->mData.getCount()==0 && iter->mRef.mRefNum.mContentFile==-1) - continue; // deleted reference that did not come from a content file -> ignore + if (!iter->mData.hasChanged() && !iter->mRef.hasChanged() && iter->mRef.getRefNum().mContentFile != -1) + { + // Reference that came from a content file and has not been changed -> ignore + continue; + } + if (iter->mData.getCount()==0 && iter->mRef.getRefNum().mContentFile==-1) + { + // Deleted reference that did not come from a content file -> ignore + continue; + } RecordType state; iter->save (state); @@ -117,7 +125,7 @@ namespace { for (typename MWWorld::CellRefList::List::iterator iter (collection.mList.begin()); iter!=collection.mList.end(); ++iter) - if (iter->mRef.mRefNum==state.mRef.mRefNum) + if (iter->mRef.getRefNum()==state.mRef.mRefNum) { // overwrite existing reference iter->load (state); diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 100e758f24..c13ecfab5a 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -82,6 +82,14 @@ namespace MWWorld return false; } + int Class::getItemHealth(const Ptr &ptr) const + { + if (ptr.getCellRef().getCharge() == -1) + return getItemMaxHealth(ptr); + else + return ptr.getCellRef().getCharge(); + } + int Class::getItemMaxHealth (const Ptr& ptr) const { throw std::runtime_error ("class does not have item health"); diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 54cea9ab01..c3f94d7f10 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -116,9 +116,12 @@ namespace MWWorld virtual bool hasItemHealth (const Ptr& ptr) const; ///< \return Item health data available? (default implementation: false) + virtual int getItemHealth (const Ptr& ptr) const; + ///< Return current item health or throw an exception if class does not have item health + virtual int getItemMaxHealth (const Ptr& ptr) const; ///< Return item max health or throw an exception, if class does not have item health - /// (default implementation: throw an exceoption) + /// (default implementation: throw an exception) virtual void hit(const Ptr& ptr, int type=-1) const; ///< Execute a melee hit, using the current weapon. This will check the relevant skills diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index d816f993bd..2496a6eff4 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -74,7 +74,6 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::getState (CellRefList ref (record); ref.load (state); - ref.mRef.mRefNum.mContentFile = -1; collection.mList.push_back (ref); return ContainerStoreIterator (this, --collection.mList.end()); @@ -127,7 +126,7 @@ int MWWorld::ContainerStore::count(const std::string &id) { int total=0; for (MWWorld::ContainerStoreIterator iter (begin()); iter!=end(); ++iter) - if (Misc::StringUtils::ciEqual(iter->getCellRef().mRefID, id)) + if (Misc::StringUtils::ciEqual(iter->getCellRef().getRefId(), id)) total += iter->getRefData().getCount(); return total; } @@ -145,7 +144,7 @@ bool MWWorld::ContainerStore::stacks(const Ptr& ptr1, const Ptr& ptr2) const MWWorld::Class& cls1 = ptr1.getClass(); const MWWorld::Class& cls2 = ptr2.getClass(); - if (!Misc::StringUtils::ciEqual(ptr1.getCellRef().mRefID, ptr2.getCellRef().mRefID)) + if (!Misc::StringUtils::ciEqual(ptr1.getCellRef().getRefId(), ptr2.getCellRef().getRefId())) return false; // If it has an enchantment, don't stack when some of the charge is already used @@ -154,25 +153,24 @@ bool MWWorld::ContainerStore::stacks(const Ptr& ptr1, const Ptr& ptr2) const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get().find( ptr1.getClass().getEnchantment(ptr1)); float maxCharge = enchantment->mData.mCharge; - float enchantCharge1 = ptr1.getCellRef().mEnchantmentCharge == -1 ? maxCharge : ptr1.getCellRef().mEnchantmentCharge; - float enchantCharge2 = ptr2.getCellRef().mEnchantmentCharge == -1 ? maxCharge : ptr2.getCellRef().mEnchantmentCharge; + float enchantCharge1 = ptr1.getCellRef().getEnchantmentCharge() == -1 ? maxCharge : ptr1.getCellRef().getEnchantmentCharge(); + float enchantCharge2 = ptr2.getCellRef().getEnchantmentCharge() == -1 ? maxCharge : ptr2.getCellRef().getEnchantmentCharge(); if (enchantCharge1 != maxCharge || enchantCharge2 != maxCharge) return false; } return ptr1 != ptr2 // an item never stacks onto itself - && ptr1.getCellRef().mOwner == ptr2.getCellRef().mOwner - && ptr1.getCellRef().mSoul == ptr2.getCellRef().mSoul + && ptr1.getCellRef().getOwner() == ptr2.getCellRef().getOwner() + && ptr1.getCellRef().getSoul() == ptr2.getCellRef().getSoul() && ptr1.getClass().getRemainingUsageTime(ptr1) == ptr2.getClass().getRemainingUsageTime(ptr2) && cls1.getScript(ptr1) == cls2.getScript(ptr2) // item that is already partly used up never stacks - && (!cls1.hasItemHealth(ptr1) || ptr1.getCellRef().mCharge == -1 - || cls1.getItemMaxHealth(ptr1) == ptr1.getCellRef().mCharge) - && (!cls2.hasItemHealth(ptr2) || ptr2.getCellRef().mCharge == -1 - || cls2.getItemMaxHealth(ptr2) == ptr2.getCellRef().mCharge); + && (!cls1.hasItemHealth(ptr1) || ( + cls1.getItemHealth(ptr1) == cls1.getItemMaxHealth(ptr1) + && cls2.getItemHealth(ptr2) == cls2.getItemMaxHealth(ptr2))); } MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add(const std::string &id, int count, const Ptr &actorPtr) @@ -195,19 +193,19 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& itemPtr { // HACK: Set owner on the original item, then reset it after we have copied it // If we set the owner on the copied item, it would not stack correctly... - std::string oldOwner = itemPtr.getCellRef().mOwner; + std::string oldOwner = itemPtr.getCellRef().getOwner(); if (actorPtr == player) { // No point in setting owner to the player - NPCs will not respect this anyway // Additionally, setting it to "player" would make those items not stack with items that don't have an owner - itemPtr.getCellRef().mOwner = ""; + itemPtr.getCellRef().setOwner(""); } else - itemPtr.getCellRef().mOwner = actorPtr.getCellRef().mRefID; + itemPtr.getCellRef().setOwner(actorPtr.getCellRef().getRefId()); it = addImp(itemPtr, count); - itemPtr.getCellRef().mOwner = oldOwner; + itemPtr.getCellRef().setOwner(oldOwner); } else { @@ -219,12 +217,14 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& itemPtr // we may have copied an item from the world, so reset a few things first item.getRefData().setBaseNode(NULL); // Especially important, otherwise scripts on the item could think that it's actually in a cell - item.getCellRef().mPos.rot[0] = 0; - item.getCellRef().mPos.rot[1] = 0; - item.getCellRef().mPos.rot[2] = 0; - item.getCellRef().mPos.pos[0] = 0; - item.getCellRef().mPos.pos[1] = 0; - item.getCellRef().mPos.pos[2] = 0; + ESM::Position pos; + pos.rot[0] = 0; + pos.rot[1] = 0; + pos.rot[2] = 0; + pos.pos[0] = 0; + pos.pos[1] = 0; + pos.pos[2] = 0; + item.getCellRef().setPosition(pos); std::string script = item.getClass().getScript(item); if(script != "") @@ -259,17 +259,17 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::addImp (const Ptr& ptr, // gold needs special handling: when it is inserted into a container, the base object automatically becomes Gold_001 // this ensures that gold piles of different sizes stack with each other (also, several scripts rely on Gold_001 for detecting player gold) - if (Misc::StringUtils::ciEqual(ptr.getCellRef().mRefID, "gold_001") - || Misc::StringUtils::ciEqual(ptr.getCellRef().mRefID, "gold_005") - || Misc::StringUtils::ciEqual(ptr.getCellRef().mRefID, "gold_010") - || Misc::StringUtils::ciEqual(ptr.getCellRef().mRefID, "gold_025") - || Misc::StringUtils::ciEqual(ptr.getCellRef().mRefID, "gold_100")) + if (Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_001") + || Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_005") + || Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_010") + || Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_025") + || Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_100")) { int realCount = count * ptr.getClass().getValue(ptr); for (MWWorld::ContainerStoreIterator iter (begin(type)); iter!=end(); ++iter) { - if (Misc::StringUtils::ciEqual((*iter).getCellRef().mRefID, MWWorld::ContainerStore::sGoldId)) + if (Misc::StringUtils::ciEqual((*iter).getCellRef().getRefId(), MWWorld::ContainerStore::sGoldId)) { iter->getRefData().setCount(iter->getRefData().getCount() + realCount); flagAsModified(); @@ -328,7 +328,7 @@ int MWWorld::ContainerStore::remove(const std::string& itemId, int count, const int toRemove = count; for (ContainerStoreIterator iter(begin()); iter != end() && toRemove > 0; ++iter) - if (Misc::StringUtils::ciEqual(iter->getCellRef().mRefID, itemId)) + if (Misc::StringUtils::ciEqual(iter->getCellRef().getRefId(), itemId)) toRemove -= remove(*iter, toRemove, actor); flagAsModified(); @@ -408,8 +408,8 @@ void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std:: } count = std::abs(count); - ref.getPtr().getCellRef().mOwner = owner; - ref.getPtr().getCellRef().mFaction = faction; + ref.getPtr().getCellRef().setOwner(owner); + ref.getPtr().getCellRef().setFaction(faction); addImp (ref.getPtr(), count); } } diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 78a2950304..2eb8aeb465 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -206,7 +206,7 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor) // Only autoEquip if we are the original owner of the item. // This stops merchants from auto equipping anything you sell to them. // ...unless this is a companion, he should always equip items given to him. - if (!Misc::StringUtils::ciEqual(test.getCellRef().mOwner, actor.getCellRef().mRefID) && + if (!Misc::StringUtils::ciEqual(test.getCellRef().getOwner(), actor.getCellRef().getRefId()) && (actor.getClass().getScript(actor).empty() || !actor.getRefData().getLocals().getIntVar(actor.getClass().getScript(actor), "companion"))) continue; @@ -337,7 +337,7 @@ void MWWorld::InventoryStore::updateMagicEffects(const Ptr& actor) std::vector params; - bool existed = (mPermanentMagicEffectMagnitudes.find((**iter).getCellRef().mRefID) != mPermanentMagicEffectMagnitudes.end()); + bool existed = (mPermanentMagicEffectMagnitudes.find((**iter).getCellRef().getRefId()) != mPermanentMagicEffectMagnitudes.end()); if (!existed) { // Roll some dice, one for each effect @@ -358,10 +358,10 @@ void MWWorld::InventoryStore::updateMagicEffects(const Ptr& actor) // Consider equipping the same item twice (e.g. a ring) // However, permanent enchantments with a random magnitude are kind of an exploit anyway, // so it doesn't really matter if both items will get the same magnitude. *Extreme* edge case. - mPermanentMagicEffectMagnitudes[(**iter).getCellRef().mRefID] = params; + mPermanentMagicEffectMagnitudes[(**iter).getCellRef().getRefId()] = params; } else - params = mPermanentMagicEffectMagnitudes[(**iter).getCellRef().mRefID]; + params = mPermanentMagicEffectMagnitudes[(**iter).getCellRef().getRefId()]; int i=0; for (std::vector::const_iterator effectIt (enchantment.mEffects.mList.begin()); @@ -407,7 +407,7 @@ void MWWorld::InventoryStore::updateMagicEffects(const Ptr& actor) { if (*iter == end()) continue; - if ((**iter).getCellRef().mRefID == it->first) + if ((**iter).getCellRef().getRefId() == it->first) { found = true; } @@ -589,14 +589,14 @@ void MWWorld::InventoryStore::visitEffectSources(MWMechanics::EffectSourceVisito if (enchantment.mData.mType != ESM::Enchantment::ConstantEffect) continue; - if (mPermanentMagicEffectMagnitudes.find((**iter).getCellRef().mRefID) == mPermanentMagicEffectMagnitudes.end()) + if (mPermanentMagicEffectMagnitudes.find((**iter).getCellRef().getRefId()) == mPermanentMagicEffectMagnitudes.end()) continue; int i=0; for (std::vector::const_iterator effectIt (enchantment.mEffects.mList.begin()); effectIt!=enchantment.mEffects.mList.end(); ++effectIt) { - const EffectParams& params = mPermanentMagicEffectMagnitudes[(**iter).getCellRef().mRefID][i]; + const EffectParams& params = mPermanentMagicEffectMagnitudes[(**iter).getCellRef().getRefId()][i]; float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * params.mRandom; magnitude *= params.mMultiplier; visitor.visit(MWMechanics::EffectKey(*effectIt), (**iter).getClass().getName(**iter), -1, magnitude); @@ -626,15 +626,15 @@ void MWWorld::InventoryStore::rechargeItems(float duration) { for (TRechargingItems::iterator it = mRechargingItems.begin(); it != mRechargingItems.end(); ++it) { - if (it->first->getCellRef().mEnchantmentCharge == -1 - || it->first->getCellRef().mEnchantmentCharge == it->second) + if (it->first->getCellRef().getEnchantmentCharge() == -1 + || it->first->getCellRef().getEnchantmentCharge() == it->second) continue; static float fMagicItemRechargePerSecond = MWBase::Environment::get().getWorld()->getStore().get().find( "fMagicItemRechargePerSecond")->getFloat(); - it->first->getCellRef().mEnchantmentCharge = std::min (it->first->getCellRef().mEnchantmentCharge + fMagicItemRechargePerSecond * duration, - it->second); + it->first->getCellRef().setEnchantmentCharge(std::min (it->first->getCellRef().getEnchantmentCharge() + fMagicItemRechargePerSecond * duration, + it->second)); } } diff --git a/apps/openmw/mwworld/livecellref.cpp b/apps/openmw/mwworld/livecellref.cpp index 1b13e38038..0921d3a1b5 100644 --- a/apps/openmw/mwworld/livecellref.cpp +++ b/apps/openmw/mwworld/livecellref.cpp @@ -11,7 +11,7 @@ #include "esmstore.hpp" MWWorld::LiveCellRefBase::LiveCellRefBase(std::string type, const ESM::CellRef &cref) - : mClass(&Class::get(type)), mRef(cref), mData(mRef) + : mClass(&Class::get(type)), mRef(cref), mData(cref) { } @@ -41,7 +41,7 @@ void MWWorld::LiveCellRefBase::loadImp (const ESM::ObjectState& state) void MWWorld::LiveCellRefBase::saveImp (ESM::ObjectState& state) const { - state.mRef = mRef; + mRef.writeState(state); /// \todo get rid of this cast once const-correct Ptr are available Ptr ptr (const_cast (this)); diff --git a/apps/openmw/mwworld/livecellref.hpp b/apps/openmw/mwworld/livecellref.hpp index b2e4d6d567..3994d8a249 100644 --- a/apps/openmw/mwworld/livecellref.hpp +++ b/apps/openmw/mwworld/livecellref.hpp @@ -3,7 +3,7 @@ #include -#include +#include "cellref.hpp" #include "refdata.hpp" @@ -26,7 +26,7 @@ namespace MWWorld /** Information about this instance, such as 3D location and rotation * and individual type-dependent data. */ - ESM::CellRef mRef; + MWWorld::CellRef mRef; /** runtime-data */ RefData mData; @@ -62,9 +62,9 @@ namespace MWWorld /// \note Does not check if the RefId exists. }; - inline bool operator== (const LiveCellRefBase& cellRef, const ESM::CellRef::RefNum refNum) + inline bool operator== (const LiveCellRefBase& cellRef, const ESM::RefNum refNum) { - return cellRef.mRef.mRefNum==refNum; + return cellRef.mRef.getRefNum()==refNum; } /// A reference to one object (of any type) in a cell. diff --git a/apps/openmw/mwworld/manualref.hpp b/apps/openmw/mwworld/manualref.hpp index 99accbb979..3842e7ff1b 100644 --- a/apps/openmw/mwworld/manualref.hpp +++ b/apps/openmw/mwworld/manualref.hpp @@ -23,10 +23,20 @@ namespace MWWorld { const T* base = list.find(name); - LiveCellRef ref; - ref.mBase = base; - ref.mRef.mRefNum.mIndex = 0; - ref.mRef.mRefNum.mContentFile = -1; + ESM::CellRef cellRef; + cellRef.mRefNum.mIndex = 0; + cellRef.mRefNum.mContentFile = -1; + cellRef.mRefID = name; + cellRef.mScale = 1; + cellRef.mFactIndex = 0; + cellRef.mCharge = -1; + cellRef.mGoldValue = 1; + cellRef.mEnchantmentCharge = -1; + cellRef.mTeleport = false; + cellRef.mLockLevel = 0; + cellRef.mReferenceBlocked = 0; + + LiveCellRef ref(cellRef, base); mRef = ref; mPtr = Ptr (&boost::any_cast&> (mRef), 0); @@ -67,19 +77,6 @@ namespace MWWorld throw std::logic_error ("failed to create manual cell ref for " + lowerName + " (unknown type)"); } - // initialise - ESM::CellRef& cellRef = mPtr.getCellRef(); - cellRef.mRefID = lowerName; - cellRef.mRefNum.mIndex = 0; - cellRef.mRefNum.mContentFile = -1; - cellRef.mScale = 1; - cellRef.mFactIndex = 0; - cellRef.mCharge = -1; - cellRef.mGoldValue = 1; - cellRef.mEnchantmentCharge = -1; - cellRef.mTeleport = false; - cellRef.mLockLevel = 0; - cellRef.mReferenceBlocked = 0; mPtr.getRefData().setCount(count); } diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 039fce0caa..b8f0f8699b 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -656,7 +656,7 @@ namespace MWWorld return false; } btVector3 btMin, btMax; - float scale = ptr.getCellRef().mScale; + float scale = ptr.getCellRef().getScale(); mEngine->getObjectAABB(model, scale, btMin, btMax); min.x = btMin.x(); diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index 5ca8f29525..9913b888b2 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -39,8 +39,10 @@ namespace MWWorld mCurrentCrimeId(-1), mPaidCrimeId(-1) { - mPlayer.mBase = player; - mPlayer.mRef.mRefID = "player"; + ESM::CellRef cellRef; + cellRef.blank(); + cellRef.mRefID = "player"; + mPlayer = LiveCellRef(cellRef, player); float* playerPos = mPlayer.mData.getPosition().pos; playerPos[0] = playerPos[1] = playerPos[2] = 0; diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 12cca27545..4e4f0b271a 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -102,11 +102,11 @@ namespace MWWorld { ProjectileState state; state.mActorId = actor.getClass().getCreatureStats(actor).getActorId(); - state.mBowId = bow.getCellRef().mRefID; + state.mBowId = bow.getCellRef().getRefId(); state.mVelocity = orient.yAxis() * speed; - state.mId = projectile.getCellRef().mRefID; + state.mId = projectile.getCellRef().getRefId(); - MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), projectile.getCellRef().mRefID); + MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), projectile.getCellRef().getRefId()); MWWorld::Ptr ptr = ref.getPtr(); state.mNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(pos, orient); @@ -241,7 +241,7 @@ namespace MWWorld { MWWorld::InventoryStore& inv = caster.getClass().getInventoryStore(caster); MWWorld::ContainerStoreIterator invIt = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); - if (invIt != inv.end() && Misc::StringUtils::ciEqual(invIt->getCellRef().mRefID, it->mBowId)) + if (invIt != inv.end() && Misc::StringUtils::ciEqual(invIt->getCellRef().getRefId(), it->mBowId)) bow = *invIt; } diff --git a/apps/openmw/mwworld/ptr.cpp b/apps/openmw/mwworld/ptr.cpp index b047ba47ca..1cf22744a8 100644 --- a/apps/openmw/mwworld/ptr.cpp +++ b/apps/openmw/mwworld/ptr.cpp @@ -22,7 +22,7 @@ MWWorld::LiveCellRefBase *MWWorld::Ptr::getBase() const return mRef; } -ESM::CellRef& MWWorld::Ptr::getCellRef() const +MWWorld::CellRef& MWWorld::Ptr::getCellRef() const { assert(mRef); diff --git a/apps/openmw/mwworld/ptr.hpp b/apps/openmw/mwworld/ptr.hpp index f4696d3b3b..2f37a1cfd8 100644 --- a/apps/openmw/mwworld/ptr.hpp +++ b/apps/openmw/mwworld/ptr.hpp @@ -60,7 +60,7 @@ namespace MWWorld MWWorld::LiveCellRefBase *getBase() const; - ESM::CellRef& getCellRef() const; + MWWorld::CellRef& getCellRef() const; RefData& getRefData() const; diff --git a/apps/openmw/mwworld/refdata.cpp b/apps/openmw/mwworld/refdata.cpp index 008782130b..2e267b37ce 100644 --- a/apps/openmw/mwworld/refdata.cpp +++ b/apps/openmw/mwworld/refdata.cpp @@ -22,6 +22,7 @@ namespace MWWorld mCount = refData.mCount; mPosition = refData.mPosition; mLocalRotation = refData.mLocalRotation; + mChanged = refData.mChanged; mCustomData = refData.mCustomData ? refData.mCustomData->clone() : 0; } @@ -35,7 +36,7 @@ namespace MWWorld } RefData::RefData() - : mBaseNode(0), mHasLocals (false), mEnabled (true), mCount (1), mCustomData (0) + : mBaseNode(0), mHasLocals (false), mEnabled (true), mCount (1), mCustomData (0), mChanged(false) { for (int i=0; i<3; ++i) { @@ -47,7 +48,8 @@ namespace MWWorld RefData::RefData (const ESM::CellRef& cellRef) : mBaseNode(0), mHasLocals (false), mEnabled (true), mCount (1), mPosition (cellRef.mPos), - mCustomData (0) + mCustomData (0), + mChanged(false) // Loading from ESM/ESP files -> assume unchanged { mLocalRotation.rot[0]=0; mLocalRotation.rot[1]=0; @@ -56,8 +58,9 @@ namespace MWWorld RefData::RefData (const ESM::ObjectState& objectState) : mBaseNode (0), mHasLocals (false), mEnabled (objectState.mEnabled), - mCount (objectState.mCount), mPosition (objectState.mPosition), mCustomData (0) - { + mCount (objectState.mCount), mPosition (objectState.mPosition), mCustomData (0), + mChanged(true) // Loading from a savegame -> assume changed + { for (int i=0; i<3; ++i) mLocalRotation.rot[i] = objectState.mLocalRotation[i]; } @@ -149,6 +152,7 @@ namespace MWWorld { mLocals.configure (script); mHasLocals = true; + mChanged = true; } } @@ -157,6 +161,8 @@ namespace MWWorld if(count == 0) MWBase::Environment::get().getWorld()->removeRefScript(this); + mChanged = true; + mCount = count; } @@ -172,26 +178,31 @@ namespace MWWorld void RefData::enable() { + mChanged = !mEnabled; mEnabled = true; } void RefData::disable() { + mChanged = mEnabled; mEnabled = false; } ESM::Position& RefData::getPosition() { + mChanged = true; return mPosition; } LocalRotation& RefData::getLocalRotation() { + mChanged = true; return mLocalRotation; } void RefData::setCustomData (CustomData *data) { + mChanged = true; // We do not currently track CustomData, so assume anything with a CustomData is changed delete mCustomData; mCustomData = data; } @@ -200,4 +211,9 @@ namespace MWWorld { return mCustomData; } + + bool RefData::hasChanged() const + { + return mChanged; + } } diff --git a/apps/openmw/mwworld/refdata.hpp b/apps/openmw/mwworld/refdata.hpp index 82371b056a..a8ffad6843 100644 --- a/apps/openmw/mwworld/refdata.hpp +++ b/apps/openmw/mwworld/refdata.hpp @@ -47,6 +47,8 @@ namespace MWWorld void cleanup(); + bool mChanged; + public: RefData(); @@ -108,6 +110,9 @@ namespace MWWorld CustomData *getCustomData(); ///< May return a 0-pointer. The ownership of the return data object is not transferred. + + bool hasChanged() const; + ///< Has this RefData changed since it was originally loaded? }; } diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 122a6f9bf5..32bf773bd5 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -47,10 +47,10 @@ namespace { if (mRescale) { - if (ptr.getCellRef().mScale<0.5) - ptr.getCellRef().mScale = 0.5; - else if (ptr.getCellRef().mScale>2) - ptr.getCellRef().mScale = 2; + if (ptr.getCellRef().getScale()<0.5) + ptr.getCellRef().setScale(0.5); + else if (ptr.getCellRef().getScale()>2) + ptr.getCellRef().setScale(2); } if (ptr.getRefData().getCount() && ptr.getRefData().isEnabled()) @@ -65,7 +65,7 @@ namespace float az = Ogre::Radian(ptr.getRefData().getLocalRotation().rot[2]).valueDegrees(); MWBase::Environment::get().getWorld()->localRotateObject (ptr, ax, ay, az); - MWBase::Environment::get().getWorld()->scaleObject (ptr, ptr.getCellRef().mScale); + MWBase::Environment::get().getWorld()->scaleObject (ptr, ptr.getCellRef().getScale()); ptr.getClass().adjustPosition (ptr); } catch (const std::exception& e) @@ -484,7 +484,7 @@ namespace MWWorld mRendering.addObject(ptr); ptr.getClass().insertObject(ptr, *mPhysics); MWBase::Environment::get().getWorld()->rotateObject(ptr, 0, 0, 0, true); - MWBase::Environment::get().getWorld()->scaleObject(ptr, ptr.getCellRef().mScale); + MWBase::Environment::get().getWorld()->scaleObject(ptr, ptr.getCellRef().getScale()); } void Scene::removeObjectFromScene (const Ptr& ptr) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 5a83a5bc74..727b200f57 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1034,7 +1034,7 @@ namespace MWWorld void World::scaleObject (const Ptr& ptr, float scale) { - ptr.getCellRef().mScale = scale; + ptr.getCellRef().setScale(scale); ptr.getClass().adjustScale(ptr,scale); if(ptr.getRefData().getBaseNode() == 0) @@ -1544,7 +1544,7 @@ namespace MWWorld if (!ref.mData.isEnabled()) continue; - if (ref.mRef.mTeleport) + if (ref.mRef.getTeleport()) { World::DoorMarker newMarker; newMarker.name = MWClass::Door::getDestination(ref); @@ -1948,7 +1948,7 @@ namespace MWWorld for (CellRefList::List::iterator container = refList.begin(); container != refList.end(); ++container) { MWWorld::Ptr ptr (&*container, *cellIt); - if (Misc::StringUtils::ciEqual(ptr.getCellRef().mOwner, npc.getCellRef().mRefID)) + if (Misc::StringUtils::ciEqual(ptr.getCellRef().getOwner(), npc.getCellRef().getRefId())) out.push_back(ptr); } } @@ -1976,7 +1976,7 @@ namespace MWWorld (*cellIt)->forEach(functor); for (std::vector::iterator it = functor.mHandles.begin(); it != functor.mHandles.end(); ++it) - if (Misc::StringUtils::ciEqual(searchPtrViaHandle(*it).getCellRef().mOwner, npc.getCellRef().mRefID)) + if (Misc::StringUtils::ciEqual(searchPtrViaHandle(*it).getCellRef().getOwner(), npc.getCellRef().getRefId())) out.push_back(searchPtrViaHandle(*it)); } } @@ -2032,34 +2032,34 @@ namespace MWWorld } const DoorList &doors = cellStore->get().mList; for (DoorList::const_iterator it = doors.begin(); it != doors.end(); ++it) { - if (!it->mRef.mTeleport) { + if (!it->mRef.getTeleport()) { continue; } MWWorld::CellStore *source = 0; // door to exterior - if (it->mRef.mDestCell.empty()) { + if (it->mRef.getDestCell().empty()) { int x, y; - const float *pos = it->mRef.mDoorDest.pos; + const float *pos = it->mRef.getDoorDest().pos; positionToIndex(pos[0], pos[1], x, y); source = getExterior(x, y); } // door to interior else { - source = getInterior(it->mRef.mDestCell); + source = getInterior(it->mRef.getDestCell()); } if (0 != source) { // Find door leading to our current teleport door // and use it destination to position inside cell. const DoorList &doors = source->get().mList; for (DoorList::const_iterator jt = doors.begin(); jt != doors.end(); ++jt) { - if (it->mRef.mTeleport && - Misc::StringUtils::ciEqual(name, jt->mRef.mDestCell)) + if (it->mRef.getTeleport() && + Misc::StringUtils::ciEqual(name, jt->mRef.getDestCell())) { /// \note Using _any_ door pointed to the interior, /// not the one pointed to current door. - pos = jt->mRef.mDoorDest; + pos = jt->mRef.getDoorDest(); return true; } } @@ -2322,9 +2322,9 @@ namespace MWWorld for (CellRefList::List::iterator it = refList.begin(); it != refList.end(); ++it) { MWWorld::LiveCellRef& ref = *it; - if (ref.mRef.mTeleport && ref.mRef.mDestCell.empty()) + if (ref.mRef.getTeleport() && ref.mRef.getDestCell().empty()) { - ESM::Position pos = ref.mRef.mDoorDest; + ESM::Position pos = ref.mRef.getDoorDest(); result = Ogre::Vector3(pos.pos); return true; } @@ -2520,13 +2520,13 @@ namespace MWWorld ContainerStore& store = ptr.getClass().getContainerStore(ptr); for (ContainerStoreIterator it = store.begin(); it != store.end(); ++it) //Move all stolen stuff into chest { - if (!it->getCellRef().mOwner.empty() && it->getCellRef().mOwner != "player") //Not owned by no one/player? + if (!it->getCellRef().getOwner().empty() && it->getCellRef().getOwner() != "player") //Not owned by no one/player? { closestChest.getClass().getContainerStore(closestChest).add(*it, it->getRefData().getCount(), closestChest); store.remove(*it, it->getRefData().getCount(), ptr); } } - closestChest.getCellRef().mLockLevel = abs(closestChest.getCellRef().mLockLevel); + closestChest.getClass().unlock(closestChest); } } @@ -2630,7 +2630,7 @@ namespace MWWorld MWWorld::CellStore* cell = mPlayer->getPlayer().getCell(); MWWorld::ManualRef ref(getStore(), selectedCreature, 1); - ref.getPtr().getCellRef().mPos = ipos; + ref.getPtr().getCellRef().setPosition(ipos); safePlaceObject(ref.getPtr(), cell, ipos); } diff --git a/components/esm/cellref.cpp b/components/esm/cellref.cpp index f04e819c88..84518bed90 100644 --- a/components/esm/cellref.cpp +++ b/components/esm/cellref.cpp @@ -168,7 +168,7 @@ void ESM::CellRef::blank() } } -bool ESM::operator== (const CellRef::RefNum& left, const CellRef::RefNum& right) +bool ESM::operator== (const RefNum& left, const RefNum& right) { return left.mIndex==right.mIndex && left.mContentFile==right.mContentFile; } diff --git a/components/esm/cellref.hpp b/components/esm/cellref.hpp index 16f6603a28..5f53eadbe3 100644 --- a/components/esm/cellref.hpp +++ b/components/esm/cellref.hpp @@ -10,6 +10,13 @@ namespace ESM class ESMWriter; class ESMReader; + + struct RefNum + { + int mIndex; + int mContentFile; // -1 no content file + }; + /* Cell reference. This represents ONE object (of many) inside the cell. The cell references are not loaded as part of the normal loading process, but are rather loaded later on demand when we are @@ -20,13 +27,10 @@ namespace ESM { public: - struct RefNum - { - int mIndex; - int mContentFile; // -1 no content file - }; + // Reference number + // Note: Currently unused for items in containers + RefNum mRefNum; - RefNum mRefNum; // Reference number std::string mRefID; // ID of object being referenced float mScale; // Scale applied to mesh @@ -38,7 +42,7 @@ namespace ESM // I have no idea, looks like a link to a global variable? std::string mGlob; - // ID of creature trapped in this soul gem (?) + // ID of creature trapped in this soul gem std::string mSoul; // The faction that owns this object (and will get angry if @@ -53,7 +57,7 @@ namespace ESM // For tools (lockpicks, probes, repair hammer) it is the remaining uses. int mCharge; - // Remaining enchantment charge + // Remaining enchantment charge. This could be -1 if the charge was not touched yet (i.e. full). float mEnchantmentCharge; // This is 5 for Gold_005 references, 100 for Gold_100 and so on. @@ -94,7 +98,7 @@ namespace ESM void blank(); }; - bool operator== (const CellRef::RefNum& left, const CellRef::RefNum& right); + bool operator== (const RefNum& left, const RefNum& right); } #endif diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index 55d043c8a4..0830c5de69 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -16,7 +16,7 @@ namespace { ///< Translate 8bit/24bit code (stored in refNum.mIndex) into a proper refNum - void adjustRefNum (ESM::CellRef::RefNum& refNum, ESM::ESMReader& reader) + void adjustRefNum (ESM::RefNum& refNum, ESM::ESMReader& reader) { int local = (refNum.mIndex & 0xff000000) >> 24; @@ -40,12 +40,12 @@ namespace ESM unsigned int Cell::sRecordId = REC_CELL; // Some overloaded compare operators. - bool operator== (const MovedCellRef& ref, const CellRef::RefNum& refNum) + bool operator== (const MovedCellRef& ref, const RefNum& refNum) { return ref.mRefNum == refNum; } - bool operator== (const CellRef& ref, const CellRef::RefNum& refNum) + bool operator== (const CellRef& ref, const RefNum& refNum) { return ref.mRefNum == refNum; } diff --git a/components/esm/loadcell.hpp b/components/esm/loadcell.hpp index f01c88c65d..28204c9ee1 100644 --- a/components/esm/loadcell.hpp +++ b/components/esm/loadcell.hpp @@ -28,7 +28,7 @@ class ESMWriter; class MovedCellRef { public: - CellRef::RefNum mRefNum; + RefNum mRefNum; // Target cell (if exterior) int mTarget[2]; @@ -39,8 +39,8 @@ public: }; /// Overloaded compare operator used to search inside a list of cell refs. -bool operator==(const MovedCellRef& ref, const CellRef::RefNum& refNum); -bool operator==(const CellRef& ref, const CellRef::RefNum& refNum); +bool operator==(const MovedCellRef& ref, const RefNum& refNum); +bool operator==(const CellRef& ref, const RefNum& refNum); typedef std::list MovedCellRefTracker; typedef std::list CellRefTracker; From 10d835a55c2d1bbd4fac3950d6253245e10a0feb Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 25 May 2014 15:06:53 +0200 Subject: [PATCH 024/151] Some more missing isInCell checks --- apps/openmw/mwscript/cellextensions.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/apps/openmw/mwscript/cellextensions.cpp b/apps/openmw/mwscript/cellextensions.cpp index ac175634bd..2e2e9b6985 100644 --- a/apps/openmw/mwscript/cellextensions.cpp +++ b/apps/openmw/mwscript/cellextensions.cpp @@ -142,6 +142,11 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { + if (!MWBase::Environment::get().getWorld()->getPlayerPtr().isInCell()) + { + runtime.push(0.f); + return; + } MWWorld::CellStore *cell = MWBase::Environment::get().getWorld()->getPlayerPtr().getCell(); if (cell->getCell()->hasWater()) runtime.push (cell->getWaterLevel()); @@ -158,6 +163,11 @@ namespace MWScript { Interpreter::Type_Float level = runtime[0].mFloat; + if (!MWBase::Environment::get().getWorld()->getPlayerPtr().isInCell()) + { + return; + } + MWWorld::CellStore *cell = MWBase::Environment::get().getWorld()->getPlayerPtr().getCell(); if (cell->getCell()->isExterior()) @@ -176,6 +186,11 @@ namespace MWScript { Interpreter::Type_Float level = runtime[0].mFloat; + if (!MWBase::Environment::get().getWorld()->getPlayerPtr().isInCell()) + { + return; + } + MWWorld::CellStore *cell = MWBase::Environment::get().getWorld()->getPlayerPtr().getCell(); if (cell->getCell()->isExterior()) From b3ffd5b868fe40e92b401f657a20717c36dc9a82 Mon Sep 17 00:00:00 2001 From: Thomas Date: Mon, 26 May 2014 01:42:11 -0400 Subject: [PATCH 025/151] 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 026/151] 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 4aab4bae6528af0caa5f0f98b5037383d3b6fa5a Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 26 May 2014 10:14:24 +0200 Subject: [PATCH 027/151] minor cleanup and silenced a warning --- apps/openmw/mwmechanics/aicombat.cpp | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index d14251886e..9ec770c9d1 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -149,7 +149,7 @@ namespace MWMechanics bool AiCombat::execute (const MWWorld::Ptr& actor,float duration) { //General description - if(actor.getClass().getCreatureStats(actor).isDead()) + if(actor.getClass().getCreatureStats(actor).isDead()) return true; MWWorld::Ptr target = MWBase::Environment::get().getWorld()->searchPtrViaActorId(mTargetActorId); @@ -157,13 +157,16 @@ namespace MWMechanics if(target.getClass().getCreatureStats(target).isDead()) 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 + const MWWorld::Class& actorClass = actor.getClass(); + MWBase::World& world = *MWBase::Environment::get().getWorld(); + + if ((!actorClass.isNpc() && target == world.getPlayerPtr() && + actorClass.canSwim(actor) && !actorClass.canWalk(actor) // pure water creature + && !world.isSwimming(target)) // Player moved out of water + || (!actorClass.canSwim(actor) && world.isSwimming(target))) // creature can't swim to Player { - actor.getClass().getCreatureStats(actor).setHostile(false); - actor.getClass().getCreatureStats(actor).setAttackingOrSpell(false); + actorClass.getCreatureStats(actor).setHostile(false); + actorClass.getCreatureStats(actor).setAttackingOrSpell(false); return true; } @@ -360,9 +363,9 @@ namespace MWMechanics 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)); + mMovement.mRotation[2] = getZAngleToDir(Ogre::Vector3(vDirToTarget.x, vDirToTarget.y, 0)); // (not quite strike dist while following) if (mFollowTarget && distToTarget > rangeAttack) @@ -408,7 +411,7 @@ namespace MWMechanics { bool preferShortcut = false; bool inLOS = MWBase::Environment::get().getWorld()->getLOS(actor, target); - + // check if shortcut is available if(inLOS && (!isStuck || mReadyToAttack) && (!mForceNoShortcut || (Ogre::Vector3(mShortcutFailPos.pos) - vActorPos).length() >= PATHFIND_SHORTCUT_RETRY_DIST)) From bfd91c0681ee766256a0295a2c3f8b0502397167 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 26 May 2014 12:31:08 +0200 Subject: [PATCH 028/151] Fix potential NpcStats overwriting issue --- apps/openmw/mwmechanics/npcstats.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index 24e758e32e..d50f2c5ae4 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -496,10 +496,10 @@ void MWMechanics::NpcStats::readState (const ESM::NpcStats& state) mExpelled.insert (iter->first); if (iter->second.mRank >= 0) - mFactionRank.insert (std::make_pair (iter->first, iter->second.mRank)); + mFactionRank[iter->first] = iter->second.mRank; if (iter->second.mReputation) - mFactionReputation.insert (std::make_pair (iter->first, iter->second.mReputation)); + mFactionReputation[iter->first] = iter->second.mReputation; } mDisposition = state.mDisposition; From f629307f6050e69cfa295cee59ffbb00b9656591 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 26 May 2014 16:43:19 +0200 Subject: [PATCH 029/151] Fix frame delay for sound listener position (Fixes #1180) --- 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 727b200f57..43153612d7 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1375,11 +1375,11 @@ namespace MWWorld updateWeather(duration); - mWorldScene->update (duration, paused); - if (!paused) doPhysics (duration); + mWorldScene->update (duration, paused); + performUpdateSceneQueries (); updateWindowManager (); From 3cd835e61a4a2e1b8e9d28fee5fa1a570459a96d Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 26 May 2014 17:34:36 +0200 Subject: [PATCH 030/151] Fix bsa file loading not being case insensitive (Fixes #1178) --- apps/openmw/mwworld/esmstore.cpp | 2 +- components/files/collections.cpp | 35 ++++++++++++++++++----- files/mygui/openmw_settings_window.layout | 2 +- 3 files changed, 30 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index 1fdf3c5a50..fc2bd4d773 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -42,7 +42,7 @@ void ESMStore::load(ESM::ESMReader &esm, Loading::Listener* listener) for (int i = 0; i < esm.getIndex(); i++) { const std::string &candidate = allPlugins->at(i).getContext().filename; std::string fnamecandidate = boost::filesystem::path(candidate).filename().string(); - if (fname == fnamecandidate) { + if (Misc::StringUtils::ciEqual(fname, fnamecandidate)) { index = i; break; } diff --git a/components/files/collections.cpp b/components/files/collections.cpp index c6195d88cf..a933eb682c 100644 --- a/components/files/collections.cpp +++ b/components/files/collections.cpp @@ -1,6 +1,7 @@ - #include "collections.hpp" +#include + namespace Files { Collections::Collections() @@ -36,9 +37,19 @@ namespace Files for (Files::PathContainer::const_iterator iter = mDirectories.begin(); iter != mDirectories.end(); ++iter) { - const boost::filesystem::path path = *iter / file; - if (boost::filesystem::exists(path)) - return path.string(); + for (boost::filesystem::directory_iterator iter2 (*iter); + iter2!=boost::filesystem::directory_iterator(); ++iter2) + { + boost::filesystem::path path = *iter2; + + if (mFoldCase) + { + if (Misc::StringUtils::ciEqual(file, path.filename().string())) + return path.string(); + } + else if (path.filename().string() == file) + return path.string(); + } } throw std::runtime_error ("file " + file + " not found"); @@ -49,9 +60,19 @@ namespace Files for (Files::PathContainer::const_iterator iter = mDirectories.begin(); iter != mDirectories.end(); ++iter) { - const boost::filesystem::path path = *iter / file; - if (boost::filesystem::exists(path)) - return true; + for (boost::filesystem::directory_iterator iter2 (*iter); + iter2!=boost::filesystem::directory_iterator(); ++iter2) + { + boost::filesystem::path path = *iter2; + + if (mFoldCase) + { + if (Misc::StringUtils::ciEqual(file, path.filename().string())) + return true; + } + else if (path.filename().string() == file) + return true; + } } return false; diff --git a/files/mygui/openmw_settings_window.layout b/files/mygui/openmw_settings_window.layout index 6119ab7b4d..9ecae465c6 100644 --- a/files/mygui/openmw_settings_window.layout +++ b/files/mygui/openmw_settings_window.layout @@ -417,7 +417,7 @@ - + From 0966755a0c8393c6276f3217f6a215f7182f72f5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 26 May 2014 19:56:32 +0200 Subject: [PATCH 031/151] Store death animation index in CreatureStats --- apps/openmw/mwmechanics/character.cpp | 56 +++++++++++++++-------- apps/openmw/mwmechanics/character.hpp | 1 + apps/openmw/mwmechanics/creaturestats.cpp | 15 +++++- apps/openmw/mwmechanics/creaturestats.hpp | 6 +++ components/esm/creaturestats.cpp | 6 +++ components/esm/creaturestats.hpp | 1 + 6 files changed, 66 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 60bccb3f7e..c9da912dd2 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -407,29 +407,25 @@ MWWorld::ContainerStoreIterator getActiveWeapon(CreatureStats &stats, MWWorld::I return inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); } -void CharacterController::playRandomDeath(float startpoint) +void CharacterController::playDeath(float startpoint, CharacterState death) { - if(MWBase::Environment::get().getWorld()->isSwimming(mPtr) && mAnimation->hasAnimation("swimdeath")) + switch (death) { - mDeathState = CharState_SwimDeath; + case CharState_SwimDeath: mCurrentDeath = "swimdeath"; - } - else if (mHitState == CharState_KnockDown) - { - mDeathState = CharState_DeathKnockDown; + break; + case CharState_DeathKnockDown: mCurrentDeath = "deathknockdown"; - } - else if (mHitState == CharState_KnockOut) - { - mDeathState = CharState_DeathKnockOut; + break; + case CharState_DeathKnockOut: mCurrentDeath = "deathknockout"; + break; + default: + mCurrentDeath = "death" + Ogre::StringConverter::toString(death - CharState_Death1 + 1); } - else - { - int selected=0; - mCurrentDeath = chooseRandomGroup("death", &selected); - mDeathState = static_cast(CharState_Death1 + (selected-1)); - } + mDeathState = death; + + mPtr.getClass().getCreatureStats(mPtr).setDeathAnimation(mDeathState - CharState_Death1); // For dead actors, refreshCurrentAnims is no longer called, so we need to disable the movement state manually. mMovementState = CharState_None; @@ -440,6 +436,29 @@ void CharacterController::playRandomDeath(float startpoint) false, 1.0f, "start", "stop", startpoint, 0); } +void CharacterController::playRandomDeath(float startpoint) +{ + if(MWBase::Environment::get().getWorld()->isSwimming(mPtr) && mAnimation->hasAnimation("swimdeath")) + { + mDeathState = CharState_SwimDeath; + } + else if (mHitState == CharState_KnockDown) + { + mDeathState = CharState_DeathKnockDown; + } + else if (mHitState == CharState_KnockOut) + { + mDeathState = CharState_DeathKnockOut; + } + else + { + int selected=0; + chooseRandomGroup("death", &selected); + mDeathState = static_cast(CharState_Death1 + (selected-1)); + } + playDeath(startpoint, mDeathState); +} + CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim) : mPtr(ptr) , mAnimation(anim) @@ -497,7 +516,8 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim if(mDeathState != CharState_None) { - playRandomDeath(1.0f); + int deathindex = mPtr.getClass().getCreatureStats(mPtr).getDeathAnimation(); + playDeath(1.0f, CharacterState(CharState_Death1 + deathindex)); } else refreshCurrentAnims(mIdleState, mMovementState, true); diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 1b7caf34d7..5cefe13bc8 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -181,6 +181,7 @@ class CharacterController void updateVisibility(); + void playDeath(float startpoint, CharacterState death); void playRandomDeath(float startpoint = 0.0f); /// choose a random animation group with \a prefix and numeric suffix diff --git a/apps/openmw/mwmechanics/creaturestats.cpp b/apps/openmw/mwmechanics/creaturestats.cpp index 3ef6ff4df9..7fd26c25c9 100644 --- a/apps/openmw/mwmechanics/creaturestats.cpp +++ b/apps/openmw/mwmechanics/creaturestats.cpp @@ -22,7 +22,8 @@ namespace MWMechanics mFallHeight(0), mRecalcDynamicStats(false), mKnockdown(false), mKnockdownOneFrame(false), mKnockdownOverOneFrame(false), mHitRecovery(false), mBlock(false), mMovementFlags(0), mDrawState (DrawState_Nothing), mAttackStrength(0.f), - mLastRestock(0,0), mGoldPool(0), mActorId(-1) + mLastRestock(0,0), mGoldPool(0), mActorId(-1), + mDeathAnimation(0) { for (int i=0; i<4; ++i) mAiSettings[i] = 0; @@ -498,6 +499,7 @@ namespace MWMechanics state.mDrawState = mDrawState; state.mLevel = mLevel; state.mActorId = mActorId; + state.mDeathAnimation = mDeathAnimation; mSpells.writeState(state.mSpells); mActiveSpells.writeState(state.mActiveSpells); @@ -537,6 +539,7 @@ namespace MWMechanics mDrawState = DrawState_(state.mDrawState); mLevel = state.mLevel; mActorId = state.mActorId; + mDeathAnimation = state.mDeathAnimation; mSpells.readState(state.mSpells); mActiveSpells.readState(state.mActiveSpells); @@ -590,4 +593,14 @@ namespace MWMechanics { esm.getHNT(sActorId, "COUN"); } + + unsigned char CreatureStats::getDeathAnimation() const + { + return mDeathAnimation; + } + + void CreatureStats::setDeathAnimation(unsigned char index) + { + mDeathAnimation = index; + } } diff --git a/apps/openmw/mwmechanics/creaturestats.hpp b/apps/openmw/mwmechanics/creaturestats.hpp index 70a86536a0..8b2398dfbd 100644 --- a/apps/openmw/mwmechanics/creaturestats.hpp +++ b/apps/openmw/mwmechanics/creaturestats.hpp @@ -64,6 +64,9 @@ namespace MWMechanics int mActorId; + // The index of the death animation that was played + unsigned char mDeathAnimation; + protected: // These two are only set by NpcStats, but they are declared in CreatureStats to prevent using virtual methods. bool mIsWerewolf; @@ -250,6 +253,9 @@ namespace MWMechanics void setGoldPool(int pool); int getGoldPool() const; + unsigned char getDeathAnimation() const; + void setDeathAnimation(unsigned char index); + int getActorId(); ///< Will generate an actor ID, if the actor does not have one yet. diff --git a/components/esm/creaturestats.cpp b/components/esm/creaturestats.cpp index 66d8481240..3860e9351f 100644 --- a/components/esm/creaturestats.cpp +++ b/components/esm/creaturestats.cpp @@ -74,6 +74,9 @@ void ESM::CreatureStats::load (ESMReader &esm) mActorId = -1; esm.getHNOT (mActorId, "ACID"); + mDeathAnimation = 0; + esm.getHNOT (mDeathAnimation, "DANM"); + mSpells.load(esm); mActiveSpells.load(esm); } @@ -152,6 +155,9 @@ void ESM::CreatureStats::save (ESMWriter &esm) const if (mActorId != -1) esm.writeHNT ("ACID", mActorId); + if (mDeathAnimation) + esm.writeHNT ("DANM", mDeathAnimation); + mSpells.save(esm); mActiveSpells.save(esm); } diff --git a/components/esm/creaturestats.hpp b/components/esm/creaturestats.hpp index 7814d937ae..5ca3d071fe 100644 --- a/components/esm/creaturestats.hpp +++ b/components/esm/creaturestats.hpp @@ -46,6 +46,7 @@ namespace ESM std::string mLastHitObject; bool mRecalcDynamicStats; int mDrawState; + unsigned char mDeathAnimation; int mLevel; From 5660f283dde88ce71ed9475c3b12a42c45075320 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 26 May 2014 20:33:01 +0200 Subject: [PATCH 032/151] Fix actor models incorrectly being rotated on X/Y axes --- apps/openmw/mwrender/actors.cpp | 13 ++++--------- apps/openmw/mwworld/worldimp.cpp | 14 ++++++++------ 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwrender/actors.cpp b/apps/openmw/mwrender/actors.cpp index a9c9884d58..b7e9f5730c 100644 --- a/apps/openmw/mwrender/actors.cpp +++ b/apps/openmw/mwrender/actors.cpp @@ -54,17 +54,12 @@ void Actors::insertBegin(const MWWorld::Ptr &ptr) // Convert MW rotation to a quaternion: f = ptr.getCellRef().getPosition().rot; - // Rotate around X axis - Ogre::Quaternion xr(Ogre::Radian(-f[0]), Ogre::Vector3::UNIT_X); - - // Rotate around Y axis - Ogre::Quaternion yr(Ogre::Radian(-f[1]), Ogre::Vector3::UNIT_Y); - - // Rotate around Z axis + // For rendering purposes, actors should only rotate around the Z axis. + // X rotation is used for camera rotation (for the player) and for + // ranged magic / ranged weapon aiming. Ogre::Quaternion zr(Ogre::Radian(-f[2]), Ogre::Vector3::UNIT_Z); - // Rotates first around z, then y, then x - insert->setOrientation(xr*yr*zr); + insert->setOrientation(zr); ptr.getRefData().setBaseNode(insert); } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 43153612d7..435ca8b367 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1116,13 +1116,15 @@ namespace MWWorld while(ptr.getRefData().getLocalRotation().rot[2]<=-fullRotateRad) ptr.getRefData().getLocalRotation().rot[2]+=fullRotateRad; - Ogre::Quaternion worldRotQuat(Ogre::Quaternion(Ogre::Radian(ptr.getRefData().getPosition().rot[0]), Ogre::Vector3::NEGATIVE_UNIT_X)* - Ogre::Quaternion(Ogre::Radian(ptr.getRefData().getPosition().rot[1]), Ogre::Vector3::NEGATIVE_UNIT_Y)* - Ogre::Quaternion(Ogre::Radian(ptr.getRefData().getPosition().rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z)); + Ogre::Quaternion worldRotQuat(Ogre::Radian(ptr.getRefData().getPosition().rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z); + if (!ptr.getClass().isActor()) + worldRotQuat = Ogre::Quaternion(Ogre::Radian(ptr.getRefData().getPosition().rot[0]), Ogre::Vector3::NEGATIVE_UNIT_X)* + Ogre::Quaternion(Ogre::Radian(ptr.getRefData().getPosition().rot[1]), Ogre::Vector3::NEGATIVE_UNIT_Y)* worldRotQuat; - Ogre::Quaternion rot(Ogre::Quaternion(Ogre::Degree(x), Ogre::Vector3::NEGATIVE_UNIT_X)* - Ogre::Quaternion(Ogre::Degree(y), Ogre::Vector3::NEGATIVE_UNIT_Y)* - Ogre::Quaternion(Ogre::Degree(z), Ogre::Vector3::NEGATIVE_UNIT_Z)); + Ogre::Quaternion rot(Ogre::Degree(z), Ogre::Vector3::NEGATIVE_UNIT_Z); + if (!ptr.getClass().isActor()) + rot = Ogre::Quaternion(Ogre::Degree(x), Ogre::Vector3::NEGATIVE_UNIT_X)* + Ogre::Quaternion(Ogre::Degree(y), Ogre::Vector3::NEGATIVE_UNIT_Y)*rot; ptr.getRefData().getBaseNode()->setOrientation(worldRotQuat*rot); mPhysics->rotateObject(ptr); From 4caa8c5ccaa31324c08b40a045f372e6fc2a5745 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 26 May 2014 20:37:12 +0200 Subject: [PATCH 033/151] Fix offset to accumulation root not being cleared when adding an animation state with startpoint=1.f (observed with death animations) --- apps/openmw/mwrender/animation.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 9124e89b88..a2f901b26a 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -775,11 +775,11 @@ void Animation::play(const std::string &groupname, int priority, int groups, boo } /* Look in reverse; last-inserted source has priority. */ + AnimState state; AnimSourceList::reverse_iterator iter(mAnimSources.rbegin()); for(;iter != mAnimSources.rend();++iter) { const NifOgre::TextKeyMap &textkeys = (*iter)->mTextKeys; - AnimState state; if(reset(state, textkeys, groupname, start, stop, startpoint)) { state.mSource = *iter; @@ -821,6 +821,13 @@ void Animation::play(const std::string &groupname, int priority, int groups, boo std::cerr<< "Failed to find animation "<setPosition(-mNonAccumCtrl->getTranslation(state.mTime)*mAccumulate); + } } bool Animation::isPlaying(const std::string &groupname) const From cf68f6da96ad4d3be5137f39e6888f25d253019e Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 27 May 2014 00:06:34 +0200 Subject: [PATCH 034/151] Fix ESX dependencies not being checked except for the first one --- apps/openmw/mwworld/esmstore.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index fc2bd4d773..03d928d2a5 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -33,12 +33,12 @@ void ESMStore::load(ESM::ESMReader &esm, Loading::Listener* listener) // Cache parent esX files by tracking their indices in the global list of // all files/readers used by the engine. This will greaty accelerate // refnumber mangling, as required for handling moved references. - int index = ~0; const std::vector &masters = esm.getGameFiles(); std::vector *allPlugins = esm.getGlobalReaderList(); for (size_t j = 0; j < masters.size(); j++) { ESM::Header::MasterData &mast = const_cast(masters[j]); std::string fname = mast.name; + int index = ~0; for (int i = 0; i < esm.getIndex(); i++) { const std::string &candidate = allPlugins->at(i).getContext().filename; std::string fnamecandidate = boost::filesystem::path(candidate).filename().string(); From e3e51324a4376bfbad1a21871873cc79dde189f9 Mon Sep 17 00:00:00 2001 From: Digmaster Date: Mon, 26 May 2014 23:13:37 -0400 Subject: [PATCH 035/151] 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 036/151] 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 037/151] 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 beba58268ce2374e10a0935f540686c814563cad Mon Sep 17 00:00:00 2001 From: Kevin Poitra Date: Tue, 27 May 2014 01:47:57 -0500 Subject: [PATCH 038/151] Fix a typo within the launcher. Fixes bug #1058. --- apps/launcher/maindialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index fb4c09b918..41d662d30b 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -806,7 +806,7 @@ void Launcher::MainDialog::play() msgBox.setWindowTitle(tr("No game file selected")); msgBox.setIcon(QMessageBox::Warning); msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(tr("
You do not have no game file selected.

\ + msgBox.setText(tr("
You do not have a game file selected.

\ OpenMW will not start without a game file selected.
")); msgBox.exec(); return; From e0356cf89d786d3fbc671220e32737fa9a379e23 Mon Sep 17 00:00:00 2001 From: Digmaster Date: Tue, 27 May 2014 03:00:31 -0400 Subject: [PATCH 039/151] 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 040/151] 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 041/151] 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 042/151] 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 d3357cc279d1ab96096648454cbb3aa8f12beaee Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Tue, 27 May 2014 13:27:18 +0200 Subject: [PATCH 043/151] The MSVC linker is really pedantic with this. Functions compiled as taking a class can't be linked with functions giving a struct, because of the name mangling I'm guessing... unresolved external symbol "protected: void __thiscall MWWorld::LiveCellRefBase::loadImp(class ESM::ObjectState const &)" (?loadImp@LiveCellRefBase@MWWorld@@IAEXABVObjectState@ESM@@@Z) --- apps/openmw/mwworld/cellref.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/cellref.hpp b/apps/openmw/mwworld/cellref.hpp index 3b0c2251be..4db362b1e0 100644 --- a/apps/openmw/mwworld/cellref.hpp +++ b/apps/openmw/mwworld/cellref.hpp @@ -5,7 +5,7 @@ namespace ESM { - class ObjectState; + struct ObjectState; } namespace MWWorld From 578adb4ef6700d4dc812190b9b285739468fe4d5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 27 May 2014 13:54:25 +0200 Subject: [PATCH 044/151] PcJoinFaction and friends: make sure the given faction exists --- apps/openmw/mwscript/statsextensions.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index d9c9e5e0b3..8b61237a1d 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -541,6 +541,9 @@ namespace MWScript runtime.pop(); } ::Misc::StringUtils::toLower(factionID); + // Make sure this faction exists + MWBase::Environment::get().getWorld()->getStore().get().find(factionID); + if(factionID != "") { MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); @@ -572,6 +575,9 @@ namespace MWScript runtime.pop(); } ::Misc::StringUtils::toLower(factionID); + // Make sure this faction exists + MWBase::Environment::get().getWorld()->getStore().get().find(factionID); + if(factionID != "") { MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); @@ -607,6 +613,9 @@ namespace MWScript runtime.pop(); } ::Misc::StringUtils::toLower(factionID); + // Make sure this faction exists + MWBase::Environment::get().getWorld()->getStore().get().find(factionID); + if(factionID != "") { MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); @@ -645,6 +654,9 @@ namespace MWScript } } ::Misc::StringUtils::toLower(factionID); + // Make sure this faction exists + MWBase::Environment::get().getWorld()->getStore().get().find(factionID); + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); if(factionID!="") { From ad911d4d033926965ed593ede3db3ec6ad6d5782 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Tue, 27 May 2014 22:09:08 +1000 Subject: [PATCH 045/151] MSVC generates different symbols for class vs struct, confusing the linker. --- apps/openmw/mwworld/cellref.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/cellref.hpp b/apps/openmw/mwworld/cellref.hpp index 3b0c2251be..4db362b1e0 100644 --- a/apps/openmw/mwworld/cellref.hpp +++ b/apps/openmw/mwworld/cellref.hpp @@ -5,7 +5,7 @@ namespace ESM { - class ObjectState; + struct ObjectState; } namespace MWWorld From e266c39c5d831a45be5fa9e6df7eef2e11ea925d Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 27 May 2014 14:54:29 +0200 Subject: [PATCH 046/151] Implement modFactionReaction instruction (Closes #1347) --- apps/openmw/mwbase/dialoguemanager.hpp | 6 +++ apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 37 +++++++++++++++++++ apps/openmw/mwdialogue/dialoguemanagerimp.hpp | 11 ++++++ apps/openmw/mwdialogue/filter.cpp | 15 ++++---- .../mwmechanics/mechanicsmanagerimp.cpp | 27 ++++++-------- apps/openmw/mwscript/dialogueextensions.cpp | 19 ++++++++++ apps/openmw/mwscript/docs/vmformat.txt | 3 +- components/compiler/extensions0.cpp | 1 + components/compiler/opcodes.hpp | 1 + components/esm/dialoguestate.cpp | 30 ++++++++++++++- components/esm/dialoguestate.hpp | 5 ++- components/esm/loadfact.cpp | 14 +++---- components/esm/loadfact.hpp | 11 ++---- 13 files changed, 138 insertions(+), 42 deletions(-) diff --git a/apps/openmw/mwbase/dialoguemanager.hpp b/apps/openmw/mwbase/dialoguemanager.hpp index f51fba07b7..cab6809aa0 100644 --- a/apps/openmw/mwbase/dialoguemanager.hpp +++ b/apps/openmw/mwbase/dialoguemanager.hpp @@ -68,6 +68,12 @@ namespace MWBase virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress) const = 0; virtual void readRecord (ESM::ESMReader& reader, int32_t type) = 0; + + /// Changes faction1's opinion of faction2 by \a diff. + virtual void modFactionReaction (const std::string& faction1, const std::string& faction2, int diff) = 0; + + /// @return faction1's opinion of faction2 + virtual int getFactionReaction (const std::string& faction1, const std::string& faction2) const = 0; }; } diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index c7e832e4ab..3ca2b8345f 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -642,6 +642,8 @@ namespace MWDialogue if (iter->second) state.mKnownTopics.push_back (iter->first); + state.mModFactionReaction = mModFactionReaction; + writer.startRecord (ESM::REC_DIAS); state.save (writer); writer.endRecord (ESM::REC_DIAS); @@ -661,9 +663,44 @@ namespace MWDialogue iter!=state.mKnownTopics.end(); ++iter) if (store.get().search (*iter)) mKnownTopics.insert (std::make_pair (*iter, true)); + + mModFactionReaction = state.mModFactionReaction; } } + void DialogueManager::modFactionReaction(const std::string &faction1, const std::string &faction2, int diff) + { + std::string fact1 = Misc::StringUtils::lowerCase(faction1); + std::string fact2 = Misc::StringUtils::lowerCase(faction2); + + // Make sure the factions exist + MWBase::Environment::get().getWorld()->getStore().get().find(fact1); + MWBase::Environment::get().getWorld()->getStore().get().find(fact2); + + std::map& map = mModFactionReaction[fact1]; + if (map.find(fact2) == map.end()) + map[fact2] = 0; + map[fact2] += diff; + } + + int DialogueManager::getFactionReaction(const std::string &faction1, const std::string &faction2) const + { + std::string fact1 = Misc::StringUtils::lowerCase(faction1); + std::string fact2 = Misc::StringUtils::lowerCase(faction2); + + ModFactionReactionMap::const_iterator map = mModFactionReaction.find(fact1); + int diff = 0; + if (map != mModFactionReaction.end() && map->second.find(fact2) != map->second.end()) + diff = map->second.at(fact2); + + const ESM::Faction* faction = MWBase::Environment::get().getWorld()->getStore().get().find(fact1); + + std::map::const_iterator it = faction->mReactions.find(fact2); + if (it == faction->mReactions.end()) + return diff; + else + return it->second + diff; + } std::vector ParseHyperText(const std::string& text) { diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp index 6cd2c75afb..db0b78d594 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp @@ -24,6 +24,11 @@ namespace MWDialogue { std::map mDialogueMap; std::map mKnownTopics;// Those are the topics the player knows. + + // Modified faction reactions. > + typedef std::map > ModFactionReactionMap; + ModFactionReactionMap mModFactionReaction; + std::list mActorKnownTopics; Translation::Storage& mTranslationDataStorage; @@ -86,6 +91,12 @@ namespace MWDialogue virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress) const; virtual void readRecord (ESM::ESMReader& reader, int32_t type); + + /// Changes faction1's opinion of faction2 by \a diff. + virtual void modFactionReaction (const std::string& faction1, const std::string& faction2, int diff); + + /// @return faction1's opinion of faction2 + virtual int getFactionReaction (const std::string& faction1, const std::string& faction2) const; }; diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index 3d67f3bce0..d301e88aac 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -396,16 +396,15 @@ int MWDialogue::Filter::getSelectStructInteger (const SelectWrapper& select) con int value = 0; - const ESM::Faction& faction = - *MWBase::Environment::get().getWorld()->getStore().get().find (factionId); - MWMechanics::NpcStats& playerStats = player.getClass().getNpcStats (player); - for (std::vector::const_iterator iter (faction.mReactions.begin()); - iter!=faction.mReactions.end(); ++iter) - if (playerStats.getFactionRanks().find (iter->mFaction)!=playerStats.getFactionRanks().end()) - if (low ? iter->mReactionmReaction>value) - value = iter->mReaction; + std::map::const_iterator playerFactionIt = playerStats.getFactionRanks().begin(); + for (; playerFactionIt != playerStats.getFactionRanks().end(); ++playerFactionIt) + { + int reaction = MWBase::Environment::get().getDialogueManager()->getFactionReaction(factionId, playerFactionIt->first); + if (low ? reaction < value : reaction > value) + value = reaction; + } return value; } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 1ea4be8432..1f9846aa71 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -498,27 +498,24 @@ namespace MWMechanics if (playerStats.getFactionRanks().find(npcFaction) != playerStats.getFactionRanks().end()) { - for(std::vector::const_iterator it = MWBase::Environment::get().getWorld()->getStore().get().find(npcFaction)->mReactions.begin(); - it != MWBase::Environment::get().getWorld()->getStore().get().find(npcFaction)->mReactions.end(); ++it) + if (!playerStats.getExpelled(npcFaction)) { - if(Misc::StringUtils::ciEqual(it->mFaction, npcFaction) - && !playerStats.getExpelled(it->mFaction)) - reaction = it->mReaction; + reaction = playerStats.getFactionReputation(npcFaction); + + rank = playerStats.getFactionRanks().find(npcFaction)->second; } - rank = playerStats.getFactionRanks().find(npcFaction)->second; } - else if (npcFaction != "") + else if (!npcFaction.empty()) { - for(std::vector::const_iterator it = MWBase::Environment::get().getWorld()->getStore().get().find(npcFaction)->mReactions.begin(); - it != MWBase::Environment::get().getWorld()->getStore().get().find(npcFaction)->mReactions.end();++it) + std::map::const_iterator playerFactionIt = playerStats.getFactionRanks().begin(); + for (; playerFactionIt != playerStats.getFactionRanks().end(); ++playerFactionIt) { - if(playerStats.getFactionRanks().find(Misc::StringUtils::lowerCase(it->mFaction)) != playerStats.getFactionRanks().end() ) - { - if(it->mReaction < reaction) - reaction = it->mReaction; - } + std::string itFaction = playerFactionIt->first; + + int itReaction = MWBase::Environment::get().getDialogueManager()->getFactionReaction(npcFaction, itFaction); + if (playerFactionIt == playerStats.getFactionRanks().begin() || itReaction < reaction) + reaction = itReaction; } - rank = 0; } else { diff --git a/apps/openmw/mwscript/dialogueextensions.cpp b/apps/openmw/mwscript/dialogueextensions.cpp index 047c4d92fa..19f6ca2df4 100644 --- a/apps/openmw/mwscript/dialogueextensions.cpp +++ b/apps/openmw/mwscript/dialogueextensions.cpp @@ -196,6 +196,24 @@ namespace MWScript } }; + class OpModFactionReaction : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + std::string faction1 = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + std::string faction2 = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + int modReaction = runtime[0].mInteger; + runtime.pop(); + + MWBase::Environment::get().getDialogueManager()->modFactionReaction(faction1, faction2, modReaction); + } + }; void installOpcodes (Interpreter::Interpreter& interpreter) { @@ -215,6 +233,7 @@ namespace MWScript interpreter.installSegment5 (Compiler::Dialogue::opcodeGetReputationExplicit, new OpGetReputation); interpreter.installSegment5 (Compiler::Dialogue::opcodeSameFaction, new OpSameFaction); interpreter.installSegment5 (Compiler::Dialogue::opcodeSameFactionExplicit, new OpSameFaction); + interpreter.installSegment5 (Compiler::Dialogue::opcodeModFactionReaction, new OpModFactionReaction); } } diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index bf2273b17e..f81cfb460c 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -390,5 +390,6 @@ op 0x200023e: GetPcInJail op 0x200023f: GetPcTraveling op 0x2000240: onKnockout op 0x2000241: onKnockoutExplicit +op 0x2000242: ModFactionReaction -opcodes 0x2000242-0x3ffffff unused +opcodes 0x2000243-0x3ffffff unused diff --git a/components/compiler/extensions0.cpp b/components/compiler/extensions0.cpp index db1ac16095..24e875173a 100644 --- a/components/compiler/extensions0.cpp +++ b/components/compiler/extensions0.cpp @@ -179,6 +179,7 @@ namespace Compiler opcodeGetReputationExplicit); extensions.registerFunction("samefaction", 'l', "", opcodeSameFaction, opcodeSameFactionExplicit); + extensions.registerInstruction("modfactionreaction", "ccl", opcodeModFactionReaction); } } diff --git a/components/compiler/opcodes.hpp b/components/compiler/opcodes.hpp index 9e36cb68d7..381a052ac2 100644 --- a/components/compiler/opcodes.hpp +++ b/components/compiler/opcodes.hpp @@ -152,6 +152,7 @@ namespace Compiler const int opcodeGetReputationExplicit = 0x20001b2; const int opcodeSameFaction = 0x20001b5; const int opcodeSameFactionExplicit = 0x20001b6; + const int opcodeModFactionReaction = 0x2000242; } namespace Gui diff --git a/components/esm/dialoguestate.cpp b/components/esm/dialoguestate.cpp index b3544c85ce..14301ac198 100644 --- a/components/esm/dialoguestate.cpp +++ b/components/esm/dialoguestate.cpp @@ -8,6 +8,20 @@ void ESM::DialogueState::load (ESMReader &esm) { while (esm.isNextSub ("TOPI")) mKnownTopics.push_back (esm.getHString()); + + while (esm.isNextSub ("FACT")) + { + std::string faction = esm.getHString(); + + while (esm.isNextSub ("REAC")) + { + std::string faction2 = esm.getHString(); + int reaction; + esm.getHNT(reaction, "INTV"); + + mModFactionReaction[faction][faction2] = reaction; + } + } } void ESM::DialogueState::save (ESMWriter &esm) const @@ -16,6 +30,18 @@ void ESM::DialogueState::save (ESMWriter &esm) const iter!=mKnownTopics.end(); ++iter) { esm.writeHNString ("TOPI", *iter); - } -} \ No newline at end of file + + for (std::map >::const_iterator iter = mModFactionReaction.begin(); + iter != mModFactionReaction.end(); ++iter) + { + esm.writeHNString ("FACT", iter->first); + + for (std::map::const_iterator reactIter = iter->second.begin(); + reactIter != iter->second.end(); ++reactIter) + { + esm.writeHNString ("REAC", reactIter->first); + esm.writeHNT ("INTV", reactIter->second); + } + } +} diff --git a/components/esm/dialoguestate.hpp b/components/esm/dialoguestate.hpp index 9aa9eaefd3..5e5f602a30 100644 --- a/components/esm/dialoguestate.hpp +++ b/components/esm/dialoguestate.hpp @@ -3,6 +3,7 @@ #include #include +#include namespace ESM { @@ -15,9 +16,11 @@ namespace ESM { std::vector mKnownTopics; + std::map > mModFactionReaction; + void load (ESMReader &esm); void save (ESMWriter &esm) const; }; } -#endif \ No newline at end of file +#endif diff --git a/components/esm/loadfact.cpp b/components/esm/loadfact.cpp index 84be21938b..0924efb174 100644 --- a/components/esm/loadfact.cpp +++ b/components/esm/loadfact.cpp @@ -44,10 +44,10 @@ void Faction::load(ESMReader &esm) // Read faction response values while (esm.hasMoreSubs()) { - Reaction r; - r.mFaction = esm.getHNString("ANAM"); - esm.getHNT(r.mReaction, "INTV"); - mReactions.push_back(r); + std::string faction = esm.getHNString("ANAM"); + int reaction; + esm.getHNT(reaction, "INTV"); + mReactions[faction] = reaction; } } void Faction::save(ESMWriter &esm) const @@ -64,10 +64,10 @@ void Faction::save(ESMWriter &esm) const esm.writeHNT("FADT", mData, 240); - for (std::vector::const_iterator it = mReactions.begin(); it != mReactions.end(); ++it) + for (std::map::const_iterator it = mReactions.begin(); it != mReactions.end(); ++it) { - esm.writeHNString("ANAM", it->mFaction); - esm.writeHNT("INTV", it->mReaction); + esm.writeHNString("ANAM", it->first); + esm.writeHNT("INTV", it->second); } } diff --git a/components/esm/loadfact.hpp b/components/esm/loadfact.hpp index 9c257e068e..75e30a5bf1 100644 --- a/components/esm/loadfact.hpp +++ b/components/esm/loadfact.hpp @@ -2,7 +2,7 @@ #define OPENMW_ESM_FACT_H #include -#include +#include namespace ESM { @@ -53,13 +53,8 @@ struct Faction FADTstruct mData; - struct Reaction - { - std::string mFaction; - int mReaction; - }; - - std::vector mReactions; + // + std::map mReactions; // Name of faction ranks (may be empty for NPC factions) std::string mRanks[10]; From 3e2eed92695405eae7372cf64fea18acd0af7abe Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 27 May 2014 15:23:22 +0200 Subject: [PATCH 047/151] Implement getFactionReaction function Strange bug when using value != 0 for the garbage argument? --- apps/openmw/mwscript/dialogueextensions.cpp | 22 +++++++++++++++++++++ apps/openmw/mwscript/docs/vmformat.txt | 3 ++- components/compiler/extensions0.cpp | 1 + components/compiler/opcodes.hpp | 1 + 4 files changed, 26 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwscript/dialogueextensions.cpp b/apps/openmw/mwscript/dialogueextensions.cpp index 19f6ca2df4..9dde65ab2c 100644 --- a/apps/openmw/mwscript/dialogueextensions.cpp +++ b/apps/openmw/mwscript/dialogueextensions.cpp @@ -215,6 +215,27 @@ namespace MWScript } }; + class OpGetFactionReaction : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + std::string faction1 = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + std::string faction2 = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + // ignore extra garbage argument + runtime.pop(); + + runtime.push(MWBase::Environment::get().getDialogueManager() + ->getFactionReaction(faction1, faction2)); + } + }; + + void installOpcodes (Interpreter::Interpreter& interpreter) { interpreter.installSegment5 (Compiler::Dialogue::opcodeJournal, new OpJournal); @@ -234,6 +255,7 @@ namespace MWScript interpreter.installSegment5 (Compiler::Dialogue::opcodeSameFaction, new OpSameFaction); interpreter.installSegment5 (Compiler::Dialogue::opcodeSameFactionExplicit, new OpSameFaction); interpreter.installSegment5 (Compiler::Dialogue::opcodeModFactionReaction, new OpModFactionReaction); + interpreter.installSegment5 (Compiler::Dialogue::opcodeGetFactionReaction, new OpGetFactionReaction); } } diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index f81cfb460c..53c80a943b 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -391,5 +391,6 @@ op 0x200023f: GetPcTraveling op 0x2000240: onKnockout op 0x2000241: onKnockoutExplicit op 0x2000242: ModFactionReaction +op 0x2000243: GetFactionReaction -opcodes 0x2000243-0x3ffffff unused +opcodes 0x2000244-0x3ffffff unused diff --git a/components/compiler/extensions0.cpp b/components/compiler/extensions0.cpp index 24e875173a..4ef638ef83 100644 --- a/components/compiler/extensions0.cpp +++ b/components/compiler/extensions0.cpp @@ -180,6 +180,7 @@ namespace Compiler extensions.registerFunction("samefaction", 'l', "", opcodeSameFaction, opcodeSameFactionExplicit); extensions.registerInstruction("modfactionreaction", "ccl", opcodeModFactionReaction); + extensions.registerFunction("getfactionreaction", 'l', "ccl", opcodeGetFactionReaction); } } diff --git a/components/compiler/opcodes.hpp b/components/compiler/opcodes.hpp index 381a052ac2..1dff046652 100644 --- a/components/compiler/opcodes.hpp +++ b/components/compiler/opcodes.hpp @@ -153,6 +153,7 @@ namespace Compiler const int opcodeSameFaction = 0x20001b5; const int opcodeSameFactionExplicit = 0x20001b6; const int opcodeModFactionReaction = 0x2000242; + const int opcodeGetFactionReaction = 0x2000243; } namespace Gui From 49a6579d3a9bce5d36530769af654ef792d7bf6e Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 27 May 2014 15:37:04 +0200 Subject: [PATCH 048/151] Fixed esmtool --- apps/esmtool/record.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index fd4b97acb9..bcf16091f4 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -707,9 +707,9 @@ void Record::print() std::cout << " Faction Reaction: " << mData.mData.mRankData[i].mFactReaction << std::endl; } - std::vector::iterator rit; + std::map::iterator rit; for (rit = mData.mReactions.begin(); rit != mData.mReactions.end(); rit++) - std::cout << " Reaction: " << rit->mReaction << " = " << rit->mFaction << std::endl; + std::cout << " Reaction: " << rit->second << " = " << rit->first << std::endl; } template<> From f476aa4ade40a21e39d8a555580bebf66b3b4e84 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 27 May 2014 17:07:14 +0200 Subject: [PATCH 049/151] Remove MyGUI color codes when copying to system clipboard --- apps/openmw/mwinput/inputmanagerimp.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index cf71cc1aa4..8cfe2c2b31 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -492,7 +492,8 @@ namespace MWInput } if (arg.keysym.sym == SDLK_x && (arg.keysym.mod & SDL_Keymod(KMOD_CTRL))) { - std::string text = edit->getTextSelection(); + // Discard color codes and other escape characters + std::string text = MyGUI::TextIterator::getOnlyText(edit->getTextSelection()); if (text.length()) { SDL_SetClipboardText(text.c_str()); @@ -504,7 +505,8 @@ namespace MWInput { if (arg.keysym.sym == SDLK_c && (arg.keysym.mod & SDL_Keymod(KMOD_CTRL))) { - std::string text = edit->getTextSelection(); + // Discard color codes and other escape characters + std::string text = MyGUI::TextIterator::getOnlyText(edit->getTextSelection()); if (text.length()) SDL_SetClipboardText(text.c_str()); } From 2fe86f2b85aa9a29f8a0d80b8982c97afc643b57 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 27 May 2014 17:39:04 +0200 Subject: [PATCH 050/151] Consider hit normal for item drop test (Fixes #995) --- apps/openmw/mwworld/physicssystem.cpp | 4 ++-- apps/openmw/mwworld/physicssystem.hpp | 5 +++-- apps/openmw/mwworld/worldimp.cpp | 13 ++++++++----- libs/openengine/bullet/physic.cpp | 8 ++++++-- libs/openengine/bullet/physic.hpp | 4 +++- 5 files changed, 22 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index b8f0f8699b..e93d9e640f 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) + std::pair PhysicsSystem::castRay(float mouseX, float mouseY, Ogre::Vector3* normal) { Ogre::Ray ray = mRender.getCamera()->getCameraToViewportRay( mouseX, @@ -504,7 +504,7 @@ namespace MWWorld _from = btVector3(from.x, from.y, from.z); _to = btVector3(to.x, to.y, to.z); - std::pair result = mEngine->rayTest(_from, _to); + std::pair result = mEngine->rayTest(_from, _to, true, false, normal); if (result.first == "") return std::make_pair(false, Ogre::Vector3()); diff --git a/apps/openmw/mwworld/physicssystem.hpp b/apps/openmw/mwworld/physicssystem.hpp index 3dcd088f54..899d7144d9 100644 --- a/apps/openmw/mwworld/physicssystem.hpp +++ b/apps/openmw/mwworld/physicssystem.hpp @@ -70,8 +70,9 @@ namespace MWWorld std::pair castRay(const Ogre::Vector3 &orig, const Ogre::Vector3 &dir, float len); - std::pair castRay(float mouseX, float mouseY); - ///< cast ray from the mouse, return true if it hit something and the first result (in OGRE coordinates) + std::pair castRay(float mouseX, float mouseY, Ogre::Vector3* normal = 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) OEngine::Physic::PhysicEngine* getEngine(); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 435ca8b367..fdc2031823 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1620,13 +1620,16 @@ namespace MWWorld bool World::canPlaceObject(float cursorX, float cursorY) { - std::pair result = mPhysics->castRay(cursorX, cursorY); + Ogre::Vector3 normal(0,0,0); + std::pair result = mPhysics->castRay(cursorX, cursorY, &normal); - /// \todo also check if the wanted position is on a flat surface, and not e.g. against a vertical wall! - - if (!result.first) + 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); + } + else return false; - return true; } diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index 6646ce2738..235300b438 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -677,7 +677,7 @@ namespace Physic { } - std::pair PhysicEngine::rayTest(btVector3& from,btVector3& to,bool raycastingObjectOnly,bool ignoreHeightMap) + std::pair PhysicEngine::rayTest(btVector3& from,btVector3& to,bool raycastingObjectOnly,bool ignoreHeightMap, Ogre::Vector3* normal) { std::string name = ""; float d = -1; @@ -694,7 +694,11 @@ namespace Physic if (resultCallback1.hasHit()) { name = static_cast(*resultCallback1.m_collisionObject).mName; - d = resultCallback1.m_closestHitFraction;; + d = resultCallback1.m_closestHitFraction; + if (normal) + *normal = Ogre::Vector3(resultCallback1.m_hitNormalWorld.x(), + resultCallback1.m_hitNormalWorld.y(), + resultCallback1.m_hitNormalWorld.z()); } return std::pair(name,d); diff --git a/libs/openengine/bullet/physic.hpp b/libs/openengine/bullet/physic.hpp index 16eb453068..803986d5b7 100644 --- a/libs/openengine/bullet/physic.hpp +++ b/libs/openengine/bullet/physic.hpp @@ -308,8 +308,10 @@ namespace Physic /** * Return the closest object hit by a ray. If there are no objects, it will return ("",-1). + * If \a normal is non-NULL, the hit normal will be written there (if there is a hit) */ - std::pair rayTest(btVector3& from,btVector3& to,bool raycastingObjectOnly = true,bool ignoreHeightMap = false); + std::pair rayTest(btVector3& from,btVector3& to,bool raycastingObjectOnly = true, + bool ignoreHeightMap = false, Ogre::Vector3* normal = NULL); /** * Return all objects hit by a ray. From 2b15b85af1472a5565310b6eae2000242198e584 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 27 May 2014 17:58:18 +0200 Subject: [PATCH 051/151] Fix position adjustment not working properly for rotated objects --- apps/openmw/mwworld/worldimp.cpp | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index fdc2031823..38edd8b8d6 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1635,13 +1635,24 @@ namespace MWWorld Ptr World::copyObjectToCell(const Ptr &object, CellStore* cell, ESM::Position pos, bool adjustPos) { - if (object.getClass().isActor() || adjustPos) + if (!object.getClass().isActor() && adjustPos) { + // Adjust position so the location we wanted ends up in the middle of the object bounding box Ogre::Vector3 min, max; if (mPhysics->getObjectAABB(object, min, max)) { - pos.pos[0] -= (min.x + max.x) / 2; - pos.pos[1] -= (min.y + max.y) / 2; - pos.pos[2] -= min.z; + Ogre::Quaternion xr(Ogre::Radian(-pos.rot[0]), Ogre::Vector3::UNIT_X); + Ogre::Quaternion yr(Ogre::Radian(-pos.rot[1]), Ogre::Vector3::UNIT_Y); + Ogre::Quaternion zr(Ogre::Radian(-pos.rot[2]), Ogre::Vector3::UNIT_Z); + + Ogre::Vector3 adjust ( + (min.x + max.x) / 2, + (min.y + max.y) / 2, + min.z + ); + adjust = (xr*yr*zr) * adjust; + pos.pos[0] -= adjust.x; + pos.pos[1] -= adjust.y; + pos.pos[2] -= adjust.z; } } From 0b45a9e6b25865143f686d5738ea45faab269e0f Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 27 May 2014 19:02:48 +0200 Subject: [PATCH 052/151] Fix case folding for faction reaction from ESX records --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 3ca2b8345f..b6cef2fe7f 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -695,11 +695,13 @@ namespace MWDialogue const ESM::Faction* faction = MWBase::Environment::get().getWorld()->getStore().get().find(fact1); - std::map::const_iterator it = faction->mReactions.find(fact2); - if (it == faction->mReactions.end()) - return diff; - else - return it->second + diff; + std::map::const_iterator it = faction->mReactions.begin(); + for (; it != faction->mReactions.end(); ++it) + { + if (Misc::StringUtils::ciEqual(it->first, fact2)) + return it->second + diff; + } + return diff; } std::vector ParseHyperText(const std::string& text) From 91f4967614795effdb0ade4cae408fc01a602313 Mon Sep 17 00:00:00 2001 From: Fil Krynicki Date: Tue, 27 May 2014 13:12:27 -0400 Subject: [PATCH 053/151] 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 054/151] 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 055/151] 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 12fc0aaecb856e4dd7966801bbdc6ebb36558e7a Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 27 May 2014 21:08:29 +0200 Subject: [PATCH 056/151] removed an unused parser settings (implicitly fixing a case were this setting was not applied correctly) --- components/compiler/exprparser.cpp | 18 +++++------------- components/compiler/exprparser.hpp | 2 +- components/compiler/lineparser.cpp | 8 ++++---- 3 files changed, 10 insertions(+), 18 deletions(-) diff --git a/components/compiler/exprparser.cpp b/components/compiler/exprparser.cpp index 0c013b18f1..90a294c0c6 100644 --- a/components/compiler/exprparser.cpp +++ b/components/compiler/exprparser.cpp @@ -730,7 +730,7 @@ namespace Compiler } int ExprParser::parseArguments (const std::string& arguments, Scanner& scanner, - std::vector& code, bool invert) + std::vector& code) { bool optional = false; int optionalCount = 0; @@ -762,15 +762,10 @@ namespace Compiler if (*iter!='x') { - if (invert) - { - std::vector tmp; - stringParser.append (tmp); + std::vector tmp; + stringParser.append (tmp); - stack.push (tmp); - } - else - stringParser.append (code); + stack.push (tmp); if (optional) ++optionalCount; @@ -795,10 +790,7 @@ namespace Compiler if (type!=*iter) Generator::convert (tmp, type, *iter); - if (invert) - stack.push (tmp); - else - std::copy (tmp.begin(), tmp.end(), std::back_inserter (code)); + stack.push (tmp); if (optional) ++optionalCount; diff --git a/components/compiler/exprparser.hpp b/components/compiler/exprparser.hpp index 93e0d1c366..e4e385ff0f 100644 --- a/components/compiler/exprparser.hpp +++ b/components/compiler/exprparser.hpp @@ -96,7 +96,7 @@ namespace Compiler /// \return Type ('l': integer, 'f': float) int parseArguments (const std::string& arguments, Scanner& scanner, - std::vector& code, bool invert = false); + std::vector& code); ///< Parse sequence of arguments specified by \a arguments. /// \param arguments Uses ScriptArgs typedef /// \see Compiler::ScriptArgs diff --git a/components/compiler/lineparser.cpp b/components/compiler/lineparser.cpp index 98bd63ba1e..f7d2726e35 100644 --- a/components/compiler/lineparser.cpp +++ b/components/compiler/lineparser.cpp @@ -166,7 +166,7 @@ namespace Compiler if (!arguments.empty()) { mExprParser.reset(); - mExprParser.parseArguments (arguments, scanner, mCode, true); + mExprParser.parseArguments (arguments, scanner, mCode); } mName = name; @@ -278,7 +278,7 @@ namespace Compiler mExplicit.clear(); } - int optionals = mExprParser.parseArguments (argumentType, scanner, mCode, true); + int optionals = mExprParser.parseArguments (argumentType, scanner, mCode); extensions->generateInstructionCode (keyword, mCode, mLiterals, mExplicit, optionals); mState = EndState; @@ -363,14 +363,14 @@ namespace Compiler case Scanner::K_startscript: - mExprParser.parseArguments ("c", scanner, mCode, true); + mExprParser.parseArguments ("c", scanner, mCode); Generator::startScript (mCode); mState = EndState; return true; case Scanner::K_stopscript: - mExprParser.parseArguments ("c", scanner, mCode, true); + mExprParser.parseArguments ("c", scanner, mCode); Generator::stopScript (mCode); mState = EndState; return true; From 9be219beba07bdd274fb9a80029827e147d36051 Mon Sep 17 00:00:00 2001 From: Arthur Moore Date: Tue, 27 May 2014 22:09:37 -0400 Subject: [PATCH 057/151] Fixes Bug #1348 "Evidence Chest unlocking when arrested." --- apps/openmw/mwworld/worldimp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 38edd8b8d6..c95a137ecc 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2542,7 +2542,7 @@ namespace MWWorld store.remove(*it, it->getRefData().getCount(), ptr); } } - closestChest.getClass().unlock(closestChest); + closestChest.getClass().lock(closestChest,50); } } From 50a4d175da4fad6aa428a59839db157614c8fa3b Mon Sep 17 00:00:00 2001 From: Arthur Moore Date: Wed, 28 May 2014 03:42:26 -0400 Subject: [PATCH 058/151] Read NIF interpolation type 4 (XYZ_ROTATION_KEY) Don't actually do anything with it yet, but without this the "MW Containers Animated" mod made containers inaccessible. Partly implements Feature #1067 --- components/nif/niffile.hpp | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/components/nif/niffile.hpp b/components/nif/niffile.hpp index d4b042726f..77e0acb9e5 100644 --- a/components/nif/niffile.hpp +++ b/components/nif/niffile.hpp @@ -155,6 +155,7 @@ struct KeyListT { static const int sLinearInterpolation = 1; static const int sQuadraticInterpolation = 2; static const int sTBCInterpolation = 3; + static const int sXYZInterpolation = 4; int mInterpolationType; VecType mKeys; @@ -199,6 +200,38 @@ struct KeyListT { key.mContinuity = nif->getFloat(); } } + //\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) + { + 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!"); + } + } else if (mInterpolationType == 0) { if (count != 0) From 3244f2197a03c51fdddc6cc4f3523bedad4fb5d0 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 28 May 2014 11:13:23 +0200 Subject: [PATCH 059/151] updated credits file --- credits.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/credits.txt b/credits.txt index 6f0561490b..da54170345 100644 --- a/credits.txt +++ b/credits.txt @@ -17,6 +17,7 @@ Alex McKibben (WeirdSexy) Alexander Nadeau (wareya) Alexander Olofsson (Ace) Artem Kotsynyak (greye) +Arthur Moore (EmperorArthur) athile Britt Mathis (galdor557) BrotherBrick From bbe77d656a99031b2fbcc31391701c1aabbf53f8 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Wed, 28 May 2014 21:15:50 +1000 Subject: [PATCH 060/151] Minor fixes from static analysis. --- apps/esmtool/labels.cpp | 6 +++--- components/compiler/exprparser.cpp | 2 +- extern/shiny/Main/Factory.hpp | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/esmtool/labels.cpp b/apps/esmtool/labels.cpp index 7a42e6900f..ef45989efe 100644 --- a/apps/esmtool/labels.cpp +++ b/apps/esmtool/labels.cpp @@ -387,7 +387,7 @@ std::string magicEffectLabel(int idx) "sEffectSummonCreature04", "sEffectSummonCreature05" }; - if (idx >= 0 && idx <= 143) + if (idx >= 0 && idx <= 142) return magicEffectLabels[idx]; else return "Invalid"; @@ -471,7 +471,7 @@ std::string skillLabel(int idx) "Speechcraft", "Hand-to-hand" }; - if (idx >= 0 && idx <= 27) + if (idx >= 0 && idx <= 26) return skillLabels[idx]; else return "Invalid"; @@ -498,7 +498,7 @@ std::string rangeTypeLabel(int idx) "Touch", "Target" }; - if (idx >= 0 && idx <= 3) + if (idx >= 0 && idx <= 2) return rangeTypeLabels[idx]; else return "Invalid"; diff --git a/components/compiler/exprparser.cpp b/components/compiler/exprparser.cpp index 90a294c0c6..ed628278b5 100644 --- a/components/compiler/exprparser.cpp +++ b/components/compiler/exprparser.cpp @@ -98,7 +98,7 @@ namespace Compiler else if (t1=='f' || t2=='f') mOperands.push_back ('f'); else - std::logic_error ("failed to determine result operand type"); + throw std::logic_error ("failed to determine result operand type"); } void ExprParser::pop() diff --git a/extern/shiny/Main/Factory.hpp b/extern/shiny/Main/Factory.hpp index 15c8599583..e8562011cb 100644 --- a/extern/shiny/Main/Factory.hpp +++ b/extern/shiny/Main/Factory.hpp @@ -206,7 +206,7 @@ namespace sh std::string getCacheFolder () { return mPlatform->getCacheFolder (); } bool getReadSourceCache() { return mReadSourceCache; } - bool getWriteSourceCache() { return mReadSourceCache; } + bool getWriteSourceCache() { return mWriteSourceCache; } public: bool getWriteMicrocodeCache() { return mWriteMicrocodeCache; } // Fixme From 56ff399f30729a5dcdb9f173d7c32c841570b4a0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 28 May 2014 13:59:31 +0200 Subject: [PATCH 061/151] 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 062/151] 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 063/151] 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 064/151] 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 065/151] 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 066/151] 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 067/151] 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 068/151] 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 069/151] 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 070/151] 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 071/151] 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 072/151] 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 073/151] 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 074/151] 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 075/151] 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 076/151] 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 077/151] 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 078/151] 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 079/151] 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 080/151] 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 081/151] 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 082/151] 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 083/151] 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 084/151] 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 085/151] 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 086/151] 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 087/151] 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 088/151] 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 089/151] 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 090/151] 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 091/151] 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 092/151] 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 093/151] 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 094/151] 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 095/151] 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 096/151] 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 097/151] 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 098/151] 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 099/151] 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 100/151] 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 101/151] 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 102/151] 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 103/151] 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 104/151] 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 105/151] 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 106/151] 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 107/151] 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 108/151] 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 109/151] 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 110/151] 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 111/151] 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 112/151] 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 113/151] 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 114/151] 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 115/151] 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 116/151] 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 117/151] 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 118/151] 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 119/151] 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 120/151] 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 121/151] 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 122/151] 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 123/151] 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 124/151] 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 125/151] 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 126/151] 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 127/151] 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 128/151] 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 129/151] 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 130/151] 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 131/151] 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 132/151] 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 133/151] 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 134/151] 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 135/151] 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 136/151] 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 137/151] 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 138/151] 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 139/151] 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 140/151] 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 141/151] 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 142/151] 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 143/151] 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 144/151] 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 145/151] 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 146/151] 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 147/151] 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 148/151] 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 149/151] 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 150/151] 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 151/151] 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)