From 312dc84fa4743f3a8b40725d6afa4e6b1edb0d94 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 8 May 2014 20:40:45 +0200 Subject: [PATCH 01/10] Fix a bug where the player's inventory could be opened as a container If an NPC uses AiActivate on the player (i.e. to activate dialogue) precisely in the frame where the player just died, the player's inventory would be opened as a container instead. --- apps/openmw/mwclass/npc.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 6a96c955f..b548e0844 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -797,6 +797,10 @@ namespace MWClass boost::shared_ptr Npc::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const { + // player got activated by another NPC + if(ptr.getRefData().getHandle() == "player") + return boost::shared_ptr(new MWWorld::ActionTalk(actor)); + if(get(actor).isNpc() && get(actor).getNpcStats(actor).isWerewolf()) { const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); @@ -814,10 +818,6 @@ namespace MWClass if(getCreatureStats(actor).getStance(MWMechanics::CreatureStats::Stance_Sneak)) return boost::shared_ptr(new MWWorld::ActionOpen(ptr)); // stealing - // player got activated by another NPC - if(ptr.getRefData().getHandle() == "player") - return boost::shared_ptr(new MWWorld::ActionTalk(actor)); - return boost::shared_ptr(new MWWorld::ActionTalk(ptr)); } From 6e9458c07617423ae6d5b2f59f705aa1dbf19e4e Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 8 May 2014 21:04:11 +0200 Subject: [PATCH 02/10] Small fix for dropping items from inventory Some widgets prevented clicking through --- files/mygui/openmw_hud.layout | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/files/mygui/openmw_hud.layout b/files/mygui/openmw_hud.layout index 4f93b42f8..90fa1c8a5 100644 --- a/files/mygui/openmw_hud.layout +++ b/files/mygui/openmw_hud.layout @@ -3,10 +3,8 @@ - - - - + + @@ -54,6 +52,7 @@ + @@ -101,6 +100,7 @@ + From 731bc9c27563a73cc8fc4712d87efb908ae42d44 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 9 May 2014 18:45:49 +0200 Subject: [PATCH 03/10] Fix broken isClass check and renamed variable for clarity --- .../openmw/mwmechanics/mechanicsmanagerimp.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 5381af8da..eb51ddfc5 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -825,13 +825,13 @@ namespace MWMechanics commitCrime(ptr, victim, OT_Theft, item.getClass().getValue(item) * count); } - bool MechanicsManager::commitCrime(const MWWorld::Ptr &ptr, const MWWorld::Ptr &victim, OffenseType type, int arg) + bool MechanicsManager::commitCrime(const MWWorld::Ptr &player, const MWWorld::Ptr &victim, OffenseType type, int arg) { // NOTE: int arg can be from itemTaken() so DON'T modify it, since it is // passed to reportCrime later on in this function. // Only player can commit crime - if (ptr.getRefData().getHandle() != "player") + if (player.getRefData().getHandle() != "player") return false; const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore(); @@ -856,7 +856,7 @@ namespace MWMechanics // Find all the actors within the alarm radius std::vector neighbors; - mActors.getObjectsInRange(Ogre::Vector3(ptr.getRefData().getPosition().pos), + mActors.getObjectsInRange(Ogre::Vector3(player.getRefData().getPosition().pos), esmStore.get().find("fAlarmRadius")->getInt(), neighbors); int id = MWBase::Environment::get().getWorld()->getPlayer().getNewCrimeId(); @@ -864,10 +864,10 @@ namespace MWMechanics // Find actors who witnessed the crime for (std::vector::iterator it = neighbors.begin(); it != neighbors.end(); ++it) { - if (*it == ptr) continue; // not the player + if (*it == player) continue; // not the player // Was the crime seen? - if (MWBase::Environment::get().getWorld()->getLOS(ptr, *it) && awarenessCheck(ptr, *it) ) + if (MWBase::Environment::get().getWorld()->getLOS(player, *it) && awarenessCheck(player, *it) ) { // TODO: Add more messages if (type == OT_Theft) @@ -881,8 +881,8 @@ namespace MWMechanics // This applies to both NPCs and creatures // ... except if this is a guard: then the player is given a chance to pay a fine / go to jail instead - if (type == OT_Assault && !ptr.getClass().isClass(ptr, "guard")) - MWBase::Environment::get().getMechanicsManager()->startCombat(victim, ptr); + if (type == OT_Assault && !it->getClass().isClass(*it, "guard")) + MWBase::Environment::get().getMechanicsManager()->startCombat(victim, player); } // Crime reporting only applies to NPCs @@ -897,7 +897,7 @@ namespace MWMechanics // Tell everyone, including yourself for (std::vector::iterator it1 = neighbors.begin(); it1 != neighbors.end(); ++it1) { - if ( *it1 == ptr + if ( *it1 == player || !it1->getClass().isNpc()) continue; // not the player and is an NPC // Will other witnesses paticipate in crime @@ -914,7 +914,7 @@ namespace MWMechanics } } if (reported) - reportCrime(ptr, victim, type, arg); + reportCrime(player, victim, type, arg); return reported; } From 872d9be1b4ca78e0324d37015c3dee04aec54e6e Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 9 May 2014 19:19:21 +0200 Subject: [PATCH 04/10] Fix potential issue with dialogue globals Make sure they are updated throughout the conversation --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index caaf7c91f..8c425caa0 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -144,7 +144,6 @@ namespace MWDialogue //setup the list of topics known by the actor. Topics who are also on the knownTopics list will be added to the GUI updateTopics(); - updateGlobals(); //greeting const MWWorld::Store &dialogs = @@ -392,6 +391,8 @@ namespace MWDialogue win->setKeywords(keywordList); mChoice = choice; + + updateGlobals(); } void DialogueManager::keywordSelected (const std::string& keyword) From e7a004824c841ccce19acb1748c50543beadce2f Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 9 May 2014 23:58:24 +0200 Subject: [PATCH 05/10] Fix a search that should have been find --- apps/openmw/mwworld/livecellref.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/livecellref.cpp b/apps/openmw/mwworld/livecellref.cpp index 0fbb26c84..f312c2159 100644 --- a/apps/openmw/mwworld/livecellref.cpp +++ b/apps/openmw/mwworld/livecellref.cpp @@ -22,7 +22,7 @@ void MWWorld::LiveCellRefBase::loadImp (const ESM::ObjectState& state) std::string scriptId = mClass->getScript (ptr); mData.setLocals (*MWBase::Environment::get().getWorld()->getStore(). - get().search (scriptId)); + get().find (scriptId)); mData.getLocals().read (state.mLocals, scriptId); } @@ -44,4 +44,4 @@ void MWWorld::LiveCellRefBase::saveImp (ESM::ObjectState& state) const bool MWWorld::LiveCellRefBase::checkStateImp (const ESM::ObjectState& state) { return true; -} \ No newline at end of file +} From 136813a882cbf8fabcf12d2c28c8f7a97126f5f6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 May 2014 00:00:36 +0200 Subject: [PATCH 06/10] Bug #1319: Fix references not coming from a content file incorrectly overwriting each other --- apps/openmw/mwworld/cellstore.cpp | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index e5f0c4b88..1c39d2c07 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -92,14 +92,17 @@ namespace if (!record) return; - for (typename MWWorld::CellRefList::List::iterator iter (collection.mList.begin()); - iter!=collection.mList.end(); ++iter) - if (iter->mRef.mRefNum==state.mRef.mRefNum) - { - // overwrite existing reference - iter->load (state); - return; - } + if (state.mRef.mRefNum.mContentFile != -1) + { + for (typename MWWorld::CellRefList::List::iterator iter (collection.mList.begin()); + iter!=collection.mList.end(); ++iter) + if (iter->mRef.mRefNum==state.mRef.mRefNum) + { + // overwrite existing reference + iter->load (state); + return; + } + } // new reference MWWorld::LiveCellRef ref (record); From 1444cd9051cc37e789f5eb816adb310b33a4291d Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 May 2014 00:37:36 +0200 Subject: [PATCH 07/10] Fix AiCombat exception when actor has a lockpick/probe equipped. Don't make NPCs autoEquip lockpicks/probes, since they can't use them. --- apps/openmw/mwmechanics/aicombat.cpp | 6 +++++- apps/openmw/mwworld/inventorystore.cpp | 7 ++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index fdaec28b4..08d087069 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -250,6 +250,9 @@ namespace MWMechanics if (state == MWMechanics::DrawState_Spell || state == MWMechanics::DrawState_Nothing) actorCls.getCreatureStats(actor).setDrawState(MWMechanics::DrawState_Weapon); + // TODO: Check equipped weapon and equip a different one if we can't attack with it + // (e.g. no ammunition, or wrong type of ammunition equipped, etc. autoEquip is not very smart in this regard)) + //Get weapon speed and range MWWorld::ContainerStoreIterator weaponSlot = MWMechanics::getActiveWeapon(actorCls.getCreatureStats(actor), actorCls.getInventoryStore(actor), &weaptype); @@ -260,8 +263,9 @@ namespace MWMechanics MWBase::Environment::get().getWorld()->getStore().get(); weapRange = gmst.find("fHandToHandReach")->getFloat(); } - else + else if (weaptype != WeapType_PickProbe && weaptype != WeapType_Spell) { + // All other WeapTypes are actually weapons, so get is safe. weapon = weaponSlot->get()->mBase; weapRange = weapon->mData.mReach; weapSpeed = weapon->mData.mSpeed; diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 9610171b2..b18bda5e3 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -192,12 +192,17 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor) { Ptr test = *iter; - // Don't autoEquip lights + // Don't autoEquip lights. Handled in Actors::updateEquippedLight based on environment light. if (test.getTypeName() == typeid(ESM::Light).name()) { continue; } + // Don't auto-equip probes or lockpicks. NPCs can't use them (yet). And AiCombat would attempt to "attack" with them. + // NOTE: In the future AiCombat should handle equipping appropriate weapons + if (test.getTypeName() == typeid(ESM::Lockpick).name() || test.getTypeName() == typeid(ESM::Probe).name()) + continue; + // 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. From d86585b153d1c48ffee82c5ad5425be86e7960a6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 May 2014 01:06:08 +0200 Subject: [PATCH 08/10] Fix clearing of local map markers destroyWidget changes the child count, so the for loop is flawed. --- apps/openmw/mwgui/mapwindow.cpp | 30 +++++++++++++++--------------- apps/openmw/mwgui/mapwindow.hpp | 11 ++++++++--- 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 284e5c4e2..6a2228c33 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -86,6 +86,11 @@ namespace MWGui { mFogOfWar = !mFogOfWar; applyFogOfWar(); + + // clear all previous door markers + for (std::vector::iterator it = mDoorMarkerWidgets.begin(); it != mDoorMarkerWidgets.end(); ++it) + MyGUI::Gui::getInstance().destroyWidget(*it); + mDoorMarkerWidgets.clear(); } void LocalMapBase::applyFogOfWar() @@ -172,14 +177,10 @@ namespace MWGui mInterior = interior; mChanged = false; - // clear all previous markers - for (unsigned int i=0; i< mLocalMap->getChildCount(); ++i) - { - if (mLocalMap->getChildAt(i)->getName ().substr (0, 4) == "Door") - { - MyGUI::Gui::getInstance ().destroyWidget (mLocalMap->getChildAt(i)); - } - } + // clear all previous door markers + for (std::vector::iterator it = mDoorMarkerWidgets.begin(); it != mDoorMarkerWidgets.end(); ++it) + MyGUI::Gui::getInstance().destroyWidget(*it); + mDoorMarkerWidgets.clear(); // Update the map textures for (int mx=0; mx<3; ++mx) @@ -243,6 +244,8 @@ namespace MWGui // Used by tooltips to not show the tooltip if marker is hidden by fog of war markerWidget->setUserString("IsMarker", "true"); markerWidget->setUserData(markerPos); + + mDoorMarkerWidgets.push_back(markerWidget); } updateMarkers(); @@ -344,13 +347,9 @@ namespace MWGui void LocalMapBase::updateMarkers() { // clear all previous markers - for (unsigned int i=0; i< mLocalMap->getChildCount(); ++i) - { - if (mLocalMap->getChildAt(i)->getName ().substr (0, 6) == "Marker") - { - MyGUI::Gui::getInstance ().destroyWidget (mLocalMap->getChildAt(i)); - } - } + for (std::vector::iterator it = mMarkerWidgets.begin(); it != mMarkerWidgets.end(); ++it) + MyGUI::Gui::getInstance().destroyWidget(*it); + mMarkerWidgets.clear(); addDetectionMarkers(MWBase::World::Detect_Creature); addDetectionMarkers(MWBase::World::Detect_Key); @@ -373,6 +372,7 @@ namespace MWGui markerWidget->setImageTexture("textures\\menu_map_smark.dds"); markerWidget->setUserString("IsMarker", "true"); markerWidget->setUserData(markerPos); + mMarkerWidgets.push_back(markerWidget); } } diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index 7f4f18893..a28c71ac9 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -55,12 +55,13 @@ namespace MWGui bool mChanged; bool mFogOfWar; - typedef std::pair CellId; - std::vector mMarkers; - std::vector mMapWidgets; std::vector mFogWidgets; + // Keep track of created marker widgets, just to easily remove them later. + std::vector mDoorMarkerWidgets; // Doors + std::vector mMarkerWidgets; // Other markers + void applyFogOfWar(); void onMarkerFocused(MyGUI::Widget* w1, MyGUI::Widget* w2); @@ -127,6 +128,10 @@ namespace MWGui MyGUI::IntPoint mLastDragPos; bool mGlobal; + // Markers on global map + typedef std::pair CellId; + std::vector mMarkers; + MyGUI::Button* mEventBoxGlobal; MyGUI::Button* mEventBoxLocal; From 516335847879db3c1e3db3e0005bfa69b980e625 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 May 2014 01:14:12 +0200 Subject: [PATCH 09/10] Fix a crash when exiting OpenMW while the mouse cursor is over a local map marker --- apps/openmw/mwgui/mapwindow.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 6a2228c33..89517d7d1 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -41,6 +41,13 @@ namespace MWGui LocalMapBase::~LocalMapBase() { + // Clear our "lost focus" delegate for marker widgets first, otherwise it will + // fire when the widget is about to be destroyed and the mouse cursor is over it. + // At that point, other widgets may already be destroyed, so applyFogOfWar (which is called by the delegate) would crash. + for (std::vector::iterator it = mDoorMarkerWidgets.begin(); it != mDoorMarkerWidgets.end(); ++it) + (*it)->eventMouseLostFocus.clear(); + for (std::vector::iterator it = mMarkerWidgets.begin(); it != mMarkerWidgets.end(); ++it) + (*it)->eventMouseLostFocus.clear(); } void LocalMapBase::init(MyGUI::ScrollView* widget, MyGUI::ImageBox* compass, OEngine::GUI::Layout* layout, bool mapDragAndDrop) From 242e19a136e44a6f913846224b9136fb92c61367 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 May 2014 01:37:34 +0200 Subject: [PATCH 10/10] Fix crash when exiting OpenMW while dialogue/journal is opened and mouse cursor on a topic (Fixes #1300) --- apps/openmw/mwgui/bookpage.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/bookpage.cpp b/apps/openmw/mwgui/bookpage.cpp index 52682342f..6545b5d45 100644 --- a/apps/openmw/mwgui/bookpage.cpp +++ b/apps/openmw/mwgui/bookpage.cpp @@ -783,7 +783,8 @@ public: ActiveTextFormats::iterator i = mActiveTextFormats.find (Font); - mNode->outOfDate (i->second->mRenderItem); + if (mNode) + mNode->outOfDate (i->second->mRenderItem); } } @@ -1125,6 +1126,8 @@ public: protected: void onMouseLostFocus(Widget* _new) { + // NOTE: MyGUI also fires eventMouseLostFocus for widgets that are about to be destroyed (if they had focus). + // Child widgets may already be destroyed! So be careful. if (PageDisplay* pd = dynamic_cast (getSubWidgetText ())) { pd->onMouseLostFocus ();