diff --git a/.gitignore b/.gitignore index e95139b8f..45c87a2c5 100644 --- a/.gitignore +++ b/.gitignore @@ -30,6 +30,7 @@ cmake-build-* files/windows/*.aps ## qt-creator CMakeLists.txt.user* +.vs ## resources data diff --git a/CHANGELOG.md b/CHANGELOG.md index cd4b75630..675766ad9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,12 @@ 0.47.0 ------ + Bug #5358: ForceGreeting always resets the dialogue window completely Bug #5363: Enchantment autocalc not always 0/1 + Bug #5364: Script fails/stops if trying to startscript an unknown script + Bug #5367: Selecting a spell on an enchanted item per hotkey always plays the equip sound + Bug #5369: Spawnpoint in the Grazelands doesn't produce oversized creatures + Feature #5362: Show the soul gems' trapped soul in count dialog 0.46.0 ------ diff --git a/apps/openmw/mwclass/creaturelevlist.cpp b/apps/openmw/mwclass/creaturelevlist.cpp index 1f47b483f..2f3ac0d1e 100644 --- a/apps/openmw/mwclass/creaturelevlist.cpp +++ b/apps/openmw/mwclass/creaturelevlist.cpp @@ -125,6 +125,7 @@ namespace MWClass const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); MWWorld::ManualRef manualRef(store, id); manualRef.getPtr().getCellRef().setPosition(ptr.getCellRef().getPosition()); + manualRef.getPtr().getCellRef().setScale(ptr.getCellRef().getScale()); MWWorld::Ptr placed = MWBase::Environment::get().getWorld()->placeObject(manualRef.getPtr(), ptr.getCell() , ptr.getCellRef().getPosition()); customData.mSpawnActorId = placed.getClass().getCreatureStats(placed).getActorId(); customData.mSpawn = false; diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index 4eb3eabef..8d3cda6fe 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -141,8 +141,6 @@ namespace MWClass MWGui::ToolTipInfo info; - const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); - bool gold = isGold(ptr); if (gold) count *= getValue(ptr); @@ -153,18 +151,9 @@ namespace MWClass else // gold displays its count also if it's 1. countString = " (" + std::to_string(count) + ")"; - info.caption = MyGUI::TextIterator::toTagsString(getName(ptr)) + countString; + info.caption = MyGUI::TextIterator::toTagsString(getName(ptr)) + countString + MWGui::ToolTips::getSoulString(ptr.getCellRef()); info.icon = ref->mBase->mIcon; - if (ref->mRef.getSoul() != "") - { - const ESM::Creature *creature = store.get().search(ref->mRef.getSoul()); - if (creature && !creature->mName.empty()) - info.caption += " (" + creature->mName + ")"; - else if (creature) - info.caption += " (" + creature->mId + ")"; - } - std::string text; text += MWGui::ToolTips::getWeightString(ref->mBase->mData.mWeight, "#{sWeight}"); diff --git a/apps/openmw/mwgui/companionwindow.cpp b/apps/openmw/mwgui/companionwindow.cpp index c069ae885..b3f6e3339 100644 --- a/apps/openmw/mwgui/companionwindow.cpp +++ b/apps/openmw/mwgui/companionwindow.cpp @@ -16,6 +16,7 @@ #include "draganddrop.hpp" #include "countdialog.hpp" #include "widgets.hpp" +#include "tooltips.hpp" namespace { @@ -86,7 +87,8 @@ void CompanionWindow::onItemSelected(int index) if (count > 1 && !shift) { CountDialog* dialog = MWBase::Environment::get().getWindowManager()->getCountDialog(); - dialog->openCountDialog(object.getClass().getName(object), "#{sTake}", count); + std::string name = object.getClass().getName(object) + MWGui::ToolTips::getSoulString(object.getCellRef()); + dialog->openCountDialog(name, "#{sTake}", count); dialog->eventOkClicked.clear(); dialog->eventOkClicked += MyGUI::newDelegate(this, &CompanionWindow::dragItem); } diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index f0e025a33..444ce4cb1 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -25,6 +25,7 @@ #include "sortfilteritemmodel.hpp" #include "pickpocketitemmodel.hpp" #include "draganddrop.hpp" +#include "tooltips.hpp" namespace MWGui { @@ -79,7 +80,8 @@ namespace MWGui if (count > 1 && !shift) { CountDialog* dialog = MWBase::Environment::get().getWindowManager()->getCountDialog(); - dialog->openCountDialog(object.getClass().getName(object), "#{sTake}", count); + std::string name = object.getClass().getName(object) + MWGui::ToolTips::getSoulString(object.getCellRef()); + dialog->openCountDialog(name, "#{sTake}", count); dialog->eventOkClicked.clear(); dialog->eventOkClicked += MyGUI::newDelegate(this, &ContainerWindow::dragItem); } diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 6b400c172..bb3f3e4ba 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -354,7 +354,10 @@ namespace MWGui void DialogueWindow::onByeClicked(MyGUI::Widget* _sender) { if (exit()) + { + resetHistory(); MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); + } } void DialogueWindow::onSelectListItem(const std::string& topic, int id) @@ -418,9 +421,7 @@ namespace MWGui bool sameActor = (mPtr == actor); if (!sameActor) { - for (DialogueText* text : mHistoryContents) - delete text; - mHistoryContents.clear(); + // The history is not reset here mKeywords.clear(); mTopicsList->clear(); for (Link* link : mLinks) @@ -475,6 +476,13 @@ namespace MWGui mDeleteLater.clear(); } + void DialogueWindow::resetHistory() + { + for (DialogueText* text : mHistoryContents) + delete text; + mHistoryContents.clear(); + } + void DialogueWindow::setKeywords(std::list keyWords) { if (mKeywords == keyWords && isCompanion() == mIsCompanion) @@ -655,6 +663,7 @@ namespace MWGui void DialogueWindow::onGoodbyeActivated() { + resetHistory(); MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Dialogue); resetReference(); @@ -709,6 +718,7 @@ namespace MWGui void DialogueWindow::onReferenceUnavailable() { + resetHistory(); MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); } diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index 2538602c6..77c767ed8 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -156,6 +156,7 @@ namespace MWGui void updateDisposition(); void restock(); void deleteLater(); + void resetHistory(); bool mIsCompanion; std::list mKeywords; diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 653f03153..6041838f5 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -38,6 +38,7 @@ #include "tradewindow.hpp" #include "draganddrop.hpp" #include "widgets.hpp" +#include "tooltips.hpp" namespace { @@ -298,7 +299,8 @@ namespace MWGui { CountDialog* dialog = MWBase::Environment::get().getWindowManager()->getCountDialog(); std::string message = mTrading ? "#{sQuanityMenuMessage01}" : "#{sTake}"; - dialog->openCountDialog(object.getClass().getName(object), message, count); + std::string name = object.getClass().getName(object) + MWGui::ToolTips::getSoulString(object.getCellRef()); + dialog->openCountDialog(name, message, count); dialog->eventOkClicked.clear(); if (mTrading) dialog->eventOkClicked += MyGUI::newDelegate(this, &InventoryWindow::sellItem); diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index ed5328d36..39278f0fa 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -401,7 +401,8 @@ namespace MWGui return; } - MWBase::Environment::get().getWindowManager()->useItem(item); + if (!store.isEquipped(item)) + MWBase::Environment::get().getWindowManager()->useItem(item); MWWorld::ConstContainerStoreIterator rightHand = store.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); // change draw state only if the item is in player's right hand if (rightHand != store.end() && item == *rightHand) @@ -411,8 +412,8 @@ namespace MWGui } else if (key->type == Type_MagicItem) { - // equip, if it can be equipped - if (!item.getClass().getEquipmentSlots(item).first.empty()) + // equip, if it can be equipped and isn't yet equipped + if (!item.getClass().getEquipmentSlots(item).first.empty() && !store.isEquipped(item)) { MWBase::Environment::get().getWindowManager()->useItem(item); diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index b86eba651..e3250e5fe 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -647,6 +647,20 @@ namespace MWGui return " (" + MyGUI::utility::toString(value) + ")"; } + std::string ToolTips::getSoulString(const MWWorld::CellRef& cellref) + { + std::string soul = cellref.getSoul(); + if (soul.empty()) + return std::string(); + const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); + const ESM::Creature *creature = store.get().search(soul); + if (!creature) + return std::string(); + if (creature->mName.empty()) + return " (" + creature->mId + ")"; + return " (" + creature->mName + ")"; + } + std::string ToolTips::getCellRefString(const MWWorld::CellRef& cellref) { std::string ret; diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index afdc7dec0..d7bb87bdb 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -81,6 +81,9 @@ namespace MWGui static std::string getCountString(const int value); ///< @return blank string if count is 1, or else " (value)" + static std::string getSoulString(const MWWorld::CellRef& cellref); + ///< Returns a string containing the name of the creature that the ID in the cellref's soul field belongs to. + static std::string getCellRefString(const MWWorld::CellRef& cellref); ///< Returns a string containing debug tooltip information about the given cellref. diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index b102b13ce..672ccbd06 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -27,6 +27,7 @@ #include "tradeitemmodel.hpp" #include "countdialog.hpp" #include "controllers.hpp" +#include "tooltips.hpp" namespace { @@ -201,7 +202,8 @@ namespace MWGui { CountDialog* dialog = MWBase::Environment::get().getWindowManager()->getCountDialog(); std::string message = "#{sQuanityMenuMessage02}"; - dialog->openCountDialog(object.getClass().getName(object), message, count); + std::string name = object.getClass().getName(object) + MWGui::ToolTips::getSoulString(object.getCellRef()); + dialog->openCountDialog(name, message, count); dialog->eventOkClicked.clear(); dialog->eventOkClicked += MyGUI::newDelegate(this, &TradeWindow::sellItem); mItemToSell = mSortModel->mapToSource(index); diff --git a/apps/openmw/mwmechanics/security.cpp b/apps/openmw/mwmechanics/security.cpp index cafc65b99..ab286cbee 100644 --- a/apps/openmw/mwmechanics/security.cpp +++ b/apps/openmw/mwmechanics/security.cpp @@ -43,6 +43,8 @@ namespace MWMechanics x *= pickQuality * mFatigueTerm; x += fPickLockMult * lockStrength; + MWBase::Environment::get().getMechanicsManager()->unlockAttempted(mActor, lock); + resultSound = "Open Lock Fail"; if (x <= 0) resultMessage = "#{sLockImpossible}"; @@ -59,7 +61,6 @@ namespace MWMechanics resultMessage = "#{sLockFail}"; } - MWBase::Environment::get().getMechanicsManager()->unlockAttempted(mActor, lock); int uses = lockpick.getClass().getItemHealth(lockpick); --uses; lockpick.getCellRef().setCharge(uses); @@ -84,6 +85,8 @@ namespace MWMechanics x += fTrapCostMult * trapSpellPoints; x *= probeQuality * mFatigueTerm; + MWBase::Environment::get().getMechanicsManager()->unlockAttempted(mActor, trap); + resultSound = "Disarm Trap Fail"; if (x <= 0) resultMessage = "#{sTrapImpossible}"; @@ -101,7 +104,6 @@ namespace MWMechanics resultMessage = "#{sTrapFail}"; } - MWBase::Environment::get().getMechanicsManager()->unlockAttempted(mActor, trap); int uses = probe.getClass().getItemHealth(probe); --uses; probe.getCellRef().setCharge(uses); diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 21fa7f369..3f32485de 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -709,6 +709,11 @@ namespace MWMechanics } else if (effectId == ESM::MagicEffect::Open) { + if (!caster.isEmpty()) + { + MWBase::Environment::get().getMechanicsManager()->unlockAttempted(getPlayer(), target); + // Use the player instead of the caster for vanilla crime compatibility + } const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); const ESM::MagicEffect *magiceffect = store.get().find(effectId); MWRender::Animation* animation = MWBase::Environment::get().getWorld()->getAnimation(target); @@ -726,11 +731,10 @@ namespace MWMechanics target.getCellRef().unlock(); } else + { MWBase::Environment::get().getSoundManager()->playSound3D(target, "Open Lock Fail", 1.f, 1.f); + } - if (!caster.isEmpty()) - MWBase::Environment::get().getMechanicsManager()->unlockAttempted(getPlayer(), target); - // Use the player instead of the caster for vanilla crime compatibility return true; } } diff --git a/apps/openmw/mwscript/globalscripts.cpp b/apps/openmw/mwscript/globalscripts.cpp index 63b0236c8..786cce072 100644 --- a/apps/openmw/mwscript/globalscripts.cpp +++ b/apps/openmw/mwscript/globalscripts.cpp @@ -28,7 +28,7 @@ namespace MWScript if (iter==mScripts.end()) { - if (const ESM::Script *script = mStore.get().find (name)) + if (const ESM::Script *script = mStore.get().search(name)) { GlobalScriptDesc desc; desc.mRunning = true; @@ -37,6 +37,10 @@ namespace MWScript mScripts.insert (std::make_pair (name, desc)); } + else + { + Log(Debug::Error) << "Failed to add global script " << name << ": script record not found"; + } } else if (!iter->second.mRunning) { diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 51d25210d..5a9693740 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -457,7 +457,7 @@ namespace NifOsg { const Nif::NiLODNode* niLodNode = static_cast(nifNode); node = handleLodNode(niLodNode); - dataVariance = osg::Object::STATIC; + dataVariance = osg::Object::DYNAMIC; break; } case Nif::RC_NiSwitchNode: @@ -476,8 +476,8 @@ namespace NifOsg { bool enabled = nifNode->flags & Nif::NiNode::Flag_ActiveCollision; node = new CollisionSwitch(nifNode->trafo.toMatrix(), enabled); - dataVariance = osg::Object::STATIC; - + // This matrix transform must not be combined with another matrix transform. + dataVariance = osg::Object::DYNAMIC; break; } default: diff --git a/components/terrain/quadtreeworld.cpp b/components/terrain/quadtreeworld.cpp index f998b7877..05f33078f 100644 --- a/components/terrain/quadtreeworld.cpp +++ b/components/terrain/quadtreeworld.cpp @@ -215,7 +215,6 @@ private: float mMinSize; osg::ref_ptr mRootNode; - osg::ref_ptr mLodCallback; }; QuadTreeWorld::QuadTreeWorld(osg::Group *parent, osg::Group *compileRoot, Resource::ResourceSystem *resourceSystem, Storage *storage, int compMapResolution, float compMapLevel, float lodFactor, int vertexLodMod, float maxCompGeometrySize) diff --git a/docs/source/conf.py b/docs/source/conf.py index 60b25ae57..7653b94ed 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -53,7 +53,7 @@ master_doc = 'index' # General information about the project. project = u'OpenMW' -copyright = u'2017, OpenMW Team' +copyright = u'2020, OpenMW Team' # The version info for the project you're documenting, acts as replacement for