diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index 470c7040d..575accaba 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -1,6 +1,7 @@ #include "weapon.hpp" #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -261,8 +262,8 @@ namespace MWClass std::string text; - // weapon type & damage. arrows / bolts don't have his info. - if (ref->mBase->mData.mType < 12) + // weapon type & damage + if ((ref->mBase->mData.mType < 12 || Settings::Manager::getBool("show projectile damage", "Game")) && ref->mBase->mData.mType < 14) { text += "\n#{sType} "; @@ -279,6 +280,8 @@ namespace MWClass mapping[ESM::Weapon::MarksmanBow] = std::make_pair("sSkillMarksman", ""); mapping[ESM::Weapon::MarksmanCrossbow] = std::make_pair("sSkillMarksman", ""); mapping[ESM::Weapon::MarksmanThrown] = std::make_pair("sSkillMarksman", ""); + mapping[ESM::Weapon::Arrow] = std::make_pair("sSkillMarksman", ""); + mapping[ESM::Weapon::Bolt] = std::make_pair("sSkillMarksman", ""); std::string type = mapping[ref->mBase->mData.mType].first; std::string oneOrTwoHanded = mapping[ref->mBase->mData.mType].second; @@ -318,6 +321,14 @@ namespace MWClass + MWGui::ToolTips::toString(ref->mBase->mData.mHealth); } + // add reach and attack speed for melee weapon + if (ref->mBase->mData.mType < 9 && Settings::Manager::getBool("show melee info", "Game")) + { + text += MWGui::ToolTips::getPercentString(ref->mBase->mData.mReach, "#{sRange}"); + + text += MWGui::ToolTips::getPercentString(ref->mBase->mData.mSpeed, "#{sAttributeSpeed}"); + } + text += MWGui::ToolTips::getWeightString(ref->mBase->mData.mWeight, "#{sWeight}"); text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}"); diff --git a/apps/openmw/mwgui/charactercreation.cpp b/apps/openmw/mwgui/charactercreation.cpp index 9464daaf6..b2c9f1038 100644 --- a/apps/openmw/mwgui/charactercreation.cpp +++ b/apps/openmw/mwgui/charactercreation.cpp @@ -13,6 +13,7 @@ #include "../mwworld/class.hpp" #include "../mwworld/esmstore.hpp" +#include "../mwworld/player.hpp" #include "textinput.hpp" #include "race.hpp" @@ -230,10 +231,19 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->removeDialog(mReviewDialog); mReviewDialog = 0; mReviewDialog = new ReviewDialog(); - mReviewDialog->setPlayerName(mPlayerName); - mReviewDialog->setRace(mPlayerRaceId); - mReviewDialog->setClass(mPlayerClass); - mReviewDialog->setBirthSign(mPlayerBirthSignId); + + MWBase::World *world = MWBase::Environment::get().getWorld(); + + const ESM::NPC *playerNpc = world->getPlayerPtr().get()->mBase; + + const MWWorld::Player player = world->getPlayer(); + + const ESM::Class *playerClass = world->getStore().get().find(playerNpc->mClass); + + mReviewDialog->setPlayerName(playerNpc->mName); + mReviewDialog->setRace(playerNpc->mRace); + mReviewDialog->setClass(*playerClass); + mReviewDialog->setBirthSign(player.getBirthSign()); { MWWorld::Ptr player = MWMechanics::getPlayer(); diff --git a/apps/openmw/mwgui/confirmationdialog.cpp b/apps/openmw/mwgui/confirmationdialog.cpp index e4312914f..33f8dbe3e 100644 --- a/apps/openmw/mwgui/confirmationdialog.cpp +++ b/apps/openmw/mwgui/confirmationdialog.cpp @@ -17,19 +17,26 @@ namespace MWGui } void ConfirmationDialog::askForConfirmation(const std::string& message, const std::string& confirmMessage, const std::string& cancelMessage) + { + mCancelButton->setCaptionWithReplacing(cancelMessage); + mOkButton->setCaptionWithReplacing(confirmMessage); + + askForConfirmation(message); + } + + void ConfirmationDialog::askForConfirmation(const std::string& message) { setVisible(true); mMessage->setCaptionWithReplacing(message); - mCancelButton->setCaptionWithReplacing(cancelMessage); - mOkButton->setCaptionWithReplacing(confirmMessage); + int height = mMessage->getTextSize().height + 60; - int height = mMessage->getTextSize().height + 72; + int width = mMessage->getTextSize().width + 24; - mMainWidget->setSize(mMainWidget->getWidth(), height); + mMainWidget->setSize(width, height); - mMessage->setSize(mMessage->getWidth(), mMessage->getTextSize().height+24); + mMessage->setSize(mMessage->getWidth(), mMessage->getTextSize().height + 24); center(); } diff --git a/apps/openmw/mwgui/confirmationdialog.hpp b/apps/openmw/mwgui/confirmationdialog.hpp index 14caa7748..745c7a1a5 100644 --- a/apps/openmw/mwgui/confirmationdialog.hpp +++ b/apps/openmw/mwgui/confirmationdialog.hpp @@ -9,7 +9,8 @@ namespace MWGui { public: ConfirmationDialog(); - void askForConfirmation(const std::string& message, const std::string& confirmMessage="#{sOk}", const std::string& cancelMessage="#{sCancel}"); + void askForConfirmation(const std::string& message); + void askForConfirmation(const std::string& message, const std::string& confirmMessage, const std::string& cancelMessage); virtual void exit(); typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void; diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 3866c5a96..d52a307c2 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -136,6 +136,18 @@ namespace MWGui dirtyPreview(); updatePreviewSize(); + + updateEncumbranceBar(); + mItemView->update(); + notifyContentChanged(); + } + + void InventoryWindow::clear() + { + mPtr = MWWorld::Ptr(); + mTradeModel = NULL; + mSortModel = NULL; + mItemView->setModel(NULL); } void InventoryWindow::setGuiMode(GuiMode mode) @@ -340,13 +352,12 @@ namespace MWGui void InventoryWindow::open() { - mPtr = MWMechanics::getPlayer(); - - updateEncumbranceBar(); - - mItemView->update(); - - notifyContentChanged(); + if (!mPtr.isEmpty()) + { + updateEncumbranceBar(); + mItemView->update(); + notifyContentChanged(); + } adjustPanes(); } diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index 651bda590..11091c428 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -60,6 +60,8 @@ namespace MWGui void updatePlayer(); + void clear(); + void useItem(const MWWorld::Ptr& ptr); void setGuiMode(GuiMode mode); diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index 184ce0775..c4a27f7ed 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -146,6 +146,7 @@ namespace MWGui const ESM::NPC& proto = mPreview->getPrototype(); setRaceId(proto.mRace); + setGender(proto.isMale() ? GM_Male : GM_Female); recountParts(); for (unsigned int i=0; igetState(); + + // If game is running, ask for confirmation first + if (state == MWBase::StateManager::State_Running && !reallySure) + { + ConfirmationDialog* dialog = MWBase::Environment::get().getWindowManager()->getConfirmationDialog(); + dialog->askForConfirmation("#{sMessage1}"); + dialog->eventOkClicked.clear(); + dialog->eventOkClicked += MyGUI::newDelegate(this, &SaveGameDialog::onConfirmationGiven); + dialog->eventCancelClicked.clear(); + return; + } + } setVisible(false); MWBase::Environment::get().getWindowManager()->removeGuiMode (MWGui::GM_MainMenu); diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 44ee6cac1..712caea39 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -594,6 +594,14 @@ namespace MWGui return "\n" + prefix + ": " + toString(weight); } + std::string ToolTips::getPercentString(const float value, const std::string& prefix) + { + if (value == 0) + return ""; + else + return "\n" + prefix + ": " + toString(value*100) +"%"; + } + std::string ToolTips::getValueString(const int value, const std::string& prefix) { if (value == 0) diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index de5b89b7f..2db5fce34 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -63,6 +63,7 @@ namespace MWGui ///< set the screen-space position of the tooltip for focused object static std::string getWeightString(const float weight, const std::string& prefix); + static std::string getPercentString(const float value, const std::string& prefix); static std::string getValueString(const int value, const std::string& prefix); ///< @return "prefix: value" or "" if value is 0 diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 119c9f551..146f20feb 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1711,7 +1711,7 @@ namespace MWGui mCompanionWindow->resetReference(); mConsole->resetReference(); - mInventoryWindow->rebuildAvatar(); + mInventoryWindow->clear(); mSelectedSpell.clear(); diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 9c7d28fc9..1ae0e36a9 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -280,7 +280,7 @@ namespace MWMechanics } } - void Actors::engageCombat (const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2, bool againstPlayer) + void Actors::engageCombat (const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2, std::map >& cachedAllies, bool againstPlayer) { CreatureStats& creatureStats1 = actor1.getClass().getCreatureStats(actor1); if (creatureStats1.getAiSequence().isInCombat(actor2)) @@ -306,7 +306,8 @@ namespace MWMechanics // Get actors allied with actor1. Includes those following or escorting actor1, actors following or escorting those actors, (recursive) // and any actor currently being followed or escorted by actor1 std::set allies1; - getActorsSidingWith(actor1, allies1); + + getActorsSidingWith(actor1, allies1, cachedAllies); // If an ally of actor1 has been attacked by actor2 or has attacked actor2, start combat between actor1 and actor2 for (std::set::const_iterator it = allies1.begin(); it != allies1.end(); ++it) @@ -328,10 +329,10 @@ namespace MWMechanics aggressive = true; } - std::set playerFollowersAndEscorters; - getActorsSidingWith(MWMechanics::getPlayer(), playerFollowersAndEscorters); + std::set playerAllies; + getActorsSidingWith(MWMechanics::getPlayer(), playerAllies, cachedAllies); - bool isPlayerFollowerOrEscorter = std::find(playerFollowersAndEscorters.begin(), playerFollowersAndEscorters.end(), actor1) != playerFollowersAndEscorters.end(); + bool isPlayerFollowerOrEscorter = std::find(playerAllies.begin(), playerAllies.end(), actor1) != playerAllies.end(); // If actor2 and at least one actor2 are in combat with actor1, actor1 and its allies start combat with them // Doesn't apply for player followers/escorters @@ -341,7 +342,9 @@ namespace MWMechanics if (actor2.getClass().getCreatureStats(actor2).getAiSequence().isInCombat(actor1)) { std::set allies2; - getActorsSidingWith(actor2, allies2); + + getActorsSidingWith(actor2, allies2, cachedAllies); + // Check that an ally of actor2 is also in combat with actor1 for (std::set::const_iterator it = allies2.begin(); it != allies2.end(); ++it) { @@ -383,11 +386,11 @@ namespace MWMechanics // Do aggression check if actor2 is the player or a player follower or escorter if (!aggressive) { - if (againstPlayer || std::find(playerFollowersAndEscorters.begin(), playerFollowersAndEscorters.end(), actor2) != playerFollowersAndEscorters.end()) + if (againstPlayer || std::find(playerAllies.begin(), playerAllies.end(), actor2) != playerAllies.end()) { // Player followers and escorters with high fight should not initiate combat with the player or with // other player followers or escorters - if (std::find(playerFollowersAndEscorters.begin(), playerFollowersAndEscorters.end(), actor1) == playerFollowersAndEscorters.end()) + if (std::find(playerAllies.begin(), playerAllies.end(), actor1) == playerAllies.end()) aggressive = MWBase::Environment::get().getMechanicsManager()->isAggressive(actor1, actor2); } } @@ -800,6 +803,12 @@ namespace MWMechanics CharacterController* ctrl = it->second->getCharacterController(); NpcStats &stats = ptr.getClass().getNpcStats(ptr); + + // When npc stats are just initialized, mTimeToStartDrowning == -1 and we should get value from GMST + static const int fHoldBreathTime = MWBase::Environment::get().getWorld()->getStore().get().find("fHoldBreathTime")->getFloat(); + if (stats.getTimeToStartDrowning() == -1.f) + stats.setTimeToStartDrowning(fHoldBreathTime); + MWBase::World *world = MWBase::Environment::get().getWorld(); bool knockedOutUnderwater = (ctrl->isKnockedOut() && world->isUnderwater(ptr.getCell(), osg::Vec3f(ptr.getRefData().getPosition().asVec3()))); if((world->isSubmerged(ptr) || knockedOutUnderwater) @@ -1075,6 +1084,8 @@ namespace MWMechanics /// \todo move update logic to Actor class where appropriate + std::map > cachedAllies; // will be filled as engageCombat iterates + // AI and magic effects update for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) { @@ -1126,7 +1137,7 @@ namespace MWMechanics { if (it->first == iter->first || iter->first == player) // player is not AI-controlled continue; - engageCombat(iter->first, it->first, it->first == player); + engageCombat(iter->first, it->first, cachedAllies, it->first == player); } } if (timerUpdateHeadTrack == 0) @@ -1591,6 +1602,29 @@ namespace MWMechanics getActorsSidingWith(*it, out); } + void Actors::getActorsSidingWith(const MWWorld::Ptr &actor, std::set& out, std::map >& cachedAllies) { + // If we have already found actor's allies, use the cache + std::map >::const_iterator search = cachedAllies.find(actor); + if (search != cachedAllies.end()) + out.insert(search->second.begin(), search->second.end()); + else + { + std::list followers = getActorsSidingWith(actor); + for (std::list::iterator it = followers.begin(); it != followers.end(); ++it) + if (out.insert(*it).second) + getActorsSidingWith(*it, out, cachedAllies); + + // Cache ptrs and their sets of allies + cachedAllies.insert(std::make_pair(actor, out)); + for (std::set::const_iterator it = out.begin(); it != out.end(); ++it) + { + search = cachedAllies.find(*it); + if (search == cachedAllies.end()) + cachedAllies.insert(std::make_pair(*it, out)); + } + } + } + std::list Actors::getActorsFollowingIndices(const MWWorld::Ptr &actor) { std::list list; diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 20aef4c17..362c2f126 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -88,7 +88,7 @@ namespace MWMechanics @Notes: If againstPlayer = true then actor2 should be the Player. If one of the combatants is creature it should be actor1. */ - void engageCombat(const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2, bool againstPlayer); + void engageCombat(const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2, std::map >& cachedAllies, bool againstPlayer); void updateHeadTracking(const MWWorld::Ptr& actor, const MWWorld::Ptr& targetActor, MWWorld::Ptr& headTrackTarget, float& sqrHeadTrackDistance); @@ -127,6 +127,8 @@ namespace MWMechanics void getActorsFollowing(const MWWorld::Ptr &actor, std::set& out); /// Recursive version of getActorsSidingWith void getActorsSidingWith(const MWWorld::Ptr &actor, std::set& out); + /// Recursive version of getActorsSidingWith that takes, adds to and returns a cache of actors mapped to their allies + void getActorsSidingWith(const MWWorld::Ptr &actor, std::set& out, std::map >& cachedAllies); /// Get the list of AiFollow::mFollowIndex for all actors following this target std::list getActorsFollowingIndices(const MWWorld::Ptr& actor); diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index e8ad0dc1f..85749d947 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1771,8 +1771,6 @@ void CharacterController::update(float duration) float height = cls.getCreatureStats(mPtr).land(); float healthLost = getFallDamage(mPtr, height); - bool godmode = mPtr == MWMechanics::getPlayer() && MWBase::Environment::get().getWorld()->getGodModeState(); - if (healthLost > 0.0f) { const float fatigueTerm = cls.getCreatureStats(mPtr).getFatigueTerm(); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index aef9a03ca..930049ba0 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -73,6 +73,8 @@ namespace MWMechanics MWMechanics::CreatureStats& creatureStats = ptr.getClass().getCreatureStats (ptr); MWMechanics::NpcStats& npcStats = ptr.getClass().getNpcStats (ptr); + npcStats.setNeedRecalcDynamicStats(true); + const ESM::NPC *player = ptr.get()->mBase; // reset @@ -326,12 +328,16 @@ namespace MWMechanics winMgr->setValue(fbar, stats.getFatigue()); } - if(stats.getTimeToStartDrowning() != mWatchedTimeToStartDrowning) + float timeToDrown = stats.getTimeToStartDrowning(); + + if(timeToDrown != mWatchedTimeToStartDrowning) { - const float fHoldBreathTime = MWBase::Environment::get().getWorld()->getStore().get() + static const float fHoldBreathTime = MWBase::Environment::get().getWorld()->getStore().get() .find("fHoldBreathTime")->getFloat(); - mWatchedTimeToStartDrowning = stats.getTimeToStartDrowning(); - if(stats.getTimeToStartDrowning() >= fHoldBreathTime) + + mWatchedTimeToStartDrowning = timeToDrown; + + if(timeToDrown >= fHoldBreathTime || timeToDrown == -1.0) // -1.0 is a special value during initialization winMgr->setDrowningBarVisibility(false); else { diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index 0b016e69d..41f2a9b51 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -30,7 +30,7 @@ MWMechanics::NpcStats::NpcStats() , mBounty(0) , mWerewolfKills (0) , mLevelProgress(0) -, mTimeToStartDrowning(20.0) +, mTimeToStartDrowning(-1.0) // set breath to special value, it will be replaced during actor update , mIsWerewolf(false) { mSkillIncreases.resize (ESM::Attribute::Length, 0); diff --git a/apps/openmw/mwscript/containerextensions.cpp b/apps/openmw/mwscript/containerextensions.cpp index 8009345f2..b7a7cafe6 100644 --- a/apps/openmw/mwscript/containerextensions.cpp +++ b/apps/openmw/mwscript/containerextensions.cpp @@ -144,7 +144,8 @@ namespace MWScript if (::Misc::StringUtils::ciEqual(iter->getCellRef().getRefId(), item)) itemName = iter->getClass().getName(*iter); - int numRemoved = store.remove(item, count, ptr); + // Actors should not equip a replacement when items are removed with RemoveItem + int numRemoved = store.remove(item, count, ptr, false); // Spawn a messagebox (only for items removed from player's inventory) if ((numRemoved > 0) @@ -199,7 +200,8 @@ namespace MWScript else { boost::shared_ptr action = it->getClass().use(*it); - action->execute(ptr); + // No equip sound for actors other than the player + action->execute(ptr, true); } } }; diff --git a/apps/openmw/mwworld/action.cpp b/apps/openmw/mwworld/action.cpp index 5663ba38f..92e959e41 100644 --- a/apps/openmw/mwworld/action.cpp +++ b/apps/openmw/mwworld/action.cpp @@ -22,9 +22,9 @@ MWWorld::Action::Action (bool keepSound, const Ptr& target) : mKeepSound (keepSo MWWorld::Action::~Action() {} -void MWWorld::Action::execute (const Ptr& actor) +void MWWorld::Action::execute (const Ptr& actor, bool noSound) { - if(!mSoundId.empty()) + if(!mSoundId.empty() && !noSound) { if(mKeepSound && actor == MWMechanics::getPlayer()) MWBase::Environment::get().getSoundManager()->playSound(mSoundId, 1.0, 1.0, diff --git a/apps/openmw/mwworld/action.hpp b/apps/openmw/mwworld/action.hpp index 6b4dff6aa..2f9804053 100644 --- a/apps/openmw/mwworld/action.hpp +++ b/apps/openmw/mwworld/action.hpp @@ -37,7 +37,7 @@ namespace MWWorld virtual bool isNullAction() { return false; } ///< Is running this action a no-op? (default false) - void execute (const Ptr& actor); + void execute (const Ptr& actor, bool noSound = false); void setSound (const std::string& id); void setSoundOffset(float offset); diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index d9fddf7a9..a4154e125 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -398,13 +398,13 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::addNewStack (const Cons return it; } -int MWWorld::ContainerStore::remove(const std::string& itemId, int count, const Ptr& actor) +int MWWorld::ContainerStore::remove(const std::string& itemId, int count, const Ptr& actor, bool equipReplacement) { int toRemove = count; for (ContainerStoreIterator iter(begin()); iter != end() && toRemove > 0; ++iter) if (Misc::StringUtils::ciEqual(iter->getCellRef().getRefId(), itemId)) - toRemove -= remove(*iter, toRemove, actor); + toRemove -= remove(*iter, toRemove, actor, equipReplacement); flagAsModified(); @@ -412,7 +412,7 @@ int MWWorld::ContainerStore::remove(const std::string& itemId, int count, const return count - toRemove; } -int MWWorld::ContainerStore::remove(const Ptr& item, int count, const Ptr& actor) +int MWWorld::ContainerStore::remove(const Ptr& item, int count, const Ptr& actor, bool equipReplacement) { assert(this == item.getContainerStore()); diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index 9849dbf26..21e126a32 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -142,12 +142,12 @@ namespace MWWorld ContainerStoreIterator add(const std::string& id, int count, const Ptr& actorPtr); ///< Utility to construct a ManualRef and call add(ptr, count, actorPtr, true) - int remove(const std::string& itemId, int count, const Ptr& actor); + int remove(const std::string& itemId, int count, const Ptr& actor, bool equipReplacement = true); ///< Remove \a count item(s) designated by \a itemId from this container. /// /// @return the number of items actually removed - virtual int remove(const Ptr& item, int count, const Ptr& actor); + virtual int remove(const Ptr& item, int count, const Ptr& actor, bool equipReplacement = true); ///< Remove \a count item(s) designated by \a item from this inventory. /// /// @return the number of items actually removed diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index df3f30bea..44e62c755 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -654,7 +654,7 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::getSelectedEnchantItem( return mSelectedEnchantItem; } -int MWWorld::InventoryStore::remove(const Ptr& item, int count, const Ptr& actor) +int MWWorld::InventoryStore::remove(const Ptr& item, int count, const Ptr& actor, bool equipReplacement) { int retCount = ContainerStore::remove(item, count, actor); @@ -676,8 +676,9 @@ int MWWorld::InventoryStore::remove(const Ptr& item, int count, const Ptr& actor } // If an armor/clothing item is removed, try to find a replacement, - // but not for the player nor werewolves. - if (wasEquipped && (actor != MWMechanics::getPlayer()) + // but not for the player nor werewolves, and not if the RemoveItem script command + // was used (equipReplacement is false) + if (equipReplacement && wasEquipped && (actor != MWMechanics::getPlayer()) && actor.getClass().isNpc() && !actor.getClass().getNpcStats(actor).isWerewolf()) { std::string type = item.getTypeName(); diff --git a/apps/openmw/mwworld/inventorystore.hpp b/apps/openmw/mwworld/inventorystore.hpp index 05f21370a..90f7f7788 100644 --- a/apps/openmw/mwworld/inventorystore.hpp +++ b/apps/openmw/mwworld/inventorystore.hpp @@ -177,7 +177,7 @@ namespace MWWorld virtual bool stacks (const ConstPtr& ptr1, const ConstPtr& ptr2) const; ///< @return true if the two specified objects can stack with each other - virtual int remove(const Ptr& item, int count, const Ptr& actor); + virtual int remove(const Ptr& item, int count, const Ptr& actor, bool equipReplacement = true); ///< Remove \a count item(s) designated by \a item from this inventory. /// /// @return the number of items actually removed diff --git a/components/sceneutil/attach.cpp b/components/sceneutil/attach.cpp index d4f324ced..e61b8a6e0 100644 --- a/components/sceneutil/attach.cpp +++ b/components/sceneutil/attach.cpp @@ -87,6 +87,8 @@ namespace SceneUtil { osg::ref_ptr handle = new osg::Group; + osg::UserDataContainer* udc = toAttach->getUserDataContainer(); + CopyRigVisitor copyVisitor(handle, filter); toAttach->accept(copyVisitor); copyVisitor.doCopy(); @@ -96,11 +98,13 @@ namespace SceneUtil osg::ref_ptr newHandle = handle->getChild(0); handle->removeChild(newHandle); master->asGroup()->addChild(newHandle); + newHandle->setUserDataContainer(udc); return newHandle; } else { master->asGroup()->addChild(handle); + handle->setUserDataContainer(udc); return handle; } } diff --git a/docs/source/reference/modding/settings/game.rst b/docs/source/reference/modding/settings/game.rst index 1eaa22db4..31ff3dd8c 100644 --- a/docs/source/reference/modding/settings/game.rst +++ b/docs/source/reference/modding/settings/game.rst @@ -12,6 +12,28 @@ Enable visual clues for items owned by NPCs when the crosshair is on the object. The default value is 0 (no clues). This setting can only be configured by editing the settings configuration file. +show projectile damage +---------------------- + +:Type: boolean +:Range: True/False +:Default: False + +If this setting is true, damage bonus of arrows and bolts will be showed on item tooltip. + +The default value is false. This setting can only be configured by editing the settings configuration file. + +show melee info +--------------- + +:Type: boolean +:Range: True/False +:Default: False + +If this setting is true, melee weapons reach and speed will be showed on item tooltip. + +The default value is false. This setting can only be configured by editing the settings configuration file. + best attack ----------- diff --git a/files/mygui/openmw_button.skin.xml b/files/mygui/openmw_button.skin.xml index 09a4c0e39..5aee8de7a 100644 --- a/files/mygui/openmw_button.skin.xml +++ b/files/mygui/openmw_button.skin.xml @@ -111,7 +111,7 @@ - + diff --git a/files/mygui/openmw_confirmation_dialog.layout b/files/mygui/openmw_confirmation_dialog.layout index fbf779cd1..39e77cb93 100644 --- a/files/mygui/openmw_confirmation_dialog.layout +++ b/files/mygui/openmw_confirmation_dialog.layout @@ -1,10 +1,10 @@ - + - + @@ -12,14 +12,14 @@ - + - + - + diff --git a/files/mygui/openmw_count_window.layout b/files/mygui/openmw_count_window.layout index 891f9f00c..a3234c405 100644 --- a/files/mygui/openmw_count_window.layout +++ b/files/mygui/openmw_count_window.layout @@ -1,29 +1,26 @@  - + - + - - + + - + - + - - - - - + + - + diff --git a/files/mygui/openmw_list.skin.xml b/files/mygui/openmw_list.skin.xml index 9f5b2e94d..111d3bf30 100644 --- a/files/mygui/openmw_list.skin.xml +++ b/files/mygui/openmw_list.skin.xml @@ -131,9 +131,9 @@ - + - + diff --git a/files/mygui/openmw_savegame_dialog.layout b/files/mygui/openmw_savegame_dialog.layout index ca11b65f8..f18218430 100644 --- a/files/mygui/openmw_savegame_dialog.layout +++ b/files/mygui/openmw_savegame_dialog.layout @@ -1,7 +1,7 @@ - + diff --git a/files/mygui/openmw_windows.skin.xml b/files/mygui/openmw_windows.skin.xml index 423de14aa..00e6f9148 100644 --- a/files/mygui/openmw_windows.skin.xml +++ b/files/mygui/openmw_windows.skin.xml @@ -1,7 +1,7 @@ - + @@ -9,6 +9,14 @@ + + + + + + + + @@ -883,4 +891,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 6756d0e7a..ec3c2ade6 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -149,6 +149,12 @@ crosshair = true # no color, 1 is tool tip only, 2 is crosshair only, and 3 is both). show owned = 0 +# Show damage bonus of arrow and bolts. +show projectile damage = false + +# Show additional melee weapon info: reach and attack speed +show melee info = false + # Always use the best mode of attack: e.g. chop, slash or thrust. best attack = false