From 8af021d729de4b9d348a4aef5de7af6692a5143f Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 23 Sep 2018 22:03:43 +0400 Subject: [PATCH] Restore dynamic stats for actors in inactive cells (bug #1875) --- CHANGELOG.md | 1 + apps/openmw/mwbase/mechanicsmanager.hpp | 2 ++ apps/openmw/mwbase/world.hpp | 2 ++ apps/openmw/mwmechanics/actors.cpp | 19 ++++++++------- .../mwmechanics/mechanicsmanagerimp.cpp | 8 +++++++ .../mwmechanics/mechanicsmanagerimp.hpp | 2 ++ apps/openmw/mwworld/cells.cpp | 13 ++++++++++ apps/openmw/mwworld/cells.hpp | 1 + apps/openmw/mwworld/cellstore.cpp | 24 +++++++++++++++++++ apps/openmw/mwworld/cellstore.hpp | 2 ++ apps/openmw/mwworld/worldimp.cpp | 4 ++++ apps/openmw/mwworld/worldimp.hpp | 8 +++---- 12 files changed, 72 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6283d3f29..1ef504003 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ 0.45.0 ------ + Bug #1875: Actors in inactive cells don't heal from resting Bug #1990: Sunrise/sunset not set correct Bug #2131: Lustidrike's spell misses the player every time Bug #2222: Fatigue's effect on selling price is backwards diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index fe3fc5721..8137bad95 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -90,6 +90,8 @@ namespace MWBase virtual void setPlayerClass (const ESM::Class& class_) = 0; ///< Set player class to custom class. + virtual void restoreDynamicStats(MWWorld::Ptr actor, bool sleep) = 0; + virtual void rest(bool sleep) = 0; ///< If the player is sleeping or waiting, this should be called every hour. /// @param sleep is the player sleeping or waiting? diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index f44e6593b..e17935abc 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -571,6 +571,8 @@ namespace MWBase virtual bool isPlayerInJail() const = 0; + virtual void rest() = 0; + virtual void setPlayerTraveling(bool traveling) = 0; virtual bool isPlayerTraveling() const = 0; diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 92f2ba34d..7f7355eef 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -545,10 +545,10 @@ namespace MWMechanics void Actors::restoreDynamicStats (const MWWorld::Ptr& ptr, bool sleep) { - if (ptr.getClass().getCreatureStats(ptr).isDead()) + MWMechanics::CreatureStats& stats = ptr.getClass().getCreatureStats (ptr); + if (stats.isDead()) return; - MWMechanics::CreatureStats& stats = ptr.getClass().getCreatureStats (ptr); const MWWorld::Store& settings = MWBase::Environment::get().getWorld()->getStore().get(); if (sleep) @@ -565,12 +565,6 @@ namespace MWMechanics stats.setMagicka(stat); } - int endurance = stats.getAttribute (ESM::Attribute::Endurance).getModified (); - - float normalizedEncumbrance = ptr.getClass().getNormalizedEncumbrance(ptr); - if (normalizedEncumbrance > 1) - normalizedEncumbrance = 1; - // Current fatigue can be above base value due to a fortify effect. // In that case stop here and don't try to restore. DynamicStat fatigue = stats.getFatigue(); @@ -582,6 +576,12 @@ namespace MWMechanics float fFatigueReturnMult = settings.find("fFatigueReturnMult")->mValue.getFloat (); float fEndFatigueMult = settings.find("fEndFatigueMult")->mValue.getFloat (); + int endurance = stats.getAttribute (ESM::Attribute::Endurance).getModified (); + + float normalizedEncumbrance = ptr.getClass().getNormalizedEncumbrance(ptr); + if (normalizedEncumbrance > 1) + normalizedEncumbrance = 1; + float x = fFatigueReturnBase + fFatigueReturnMult * (1 - normalizedEncumbrance); x *= fEndFatigueMult * endurance; @@ -1667,7 +1667,8 @@ namespace MWMechanics if (iter->first.getClass().getCreatureStats(iter->first).isDead()) continue; - restoreDynamicStats(iter->first, sleep); + if (!sleep || iter->first == player) + restoreDynamicStats(iter->first, sleep); if ((!iter->first.getRefData().getBaseNode()) || (playerPos - iter->first.getRefData().getPosition().asVec3()).length2() > sqrAiProcessingDistance) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 859b2e522..33357b79a 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -453,9 +453,17 @@ namespace MWMechanics void MechanicsManager::rest(bool sleep) { + if (sleep) + MWBase::Environment::get().getWorld()->rest(); + mActors.rest(sleep); } + void MechanicsManager::restoreDynamicStats(MWWorld::Ptr actor, bool sleep) + { + mActors.restoreDynamicStats(actor, sleep); + } + int MechanicsManager::getHoursToRest() const { return mActors.getHoursToRest(mWatched); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index af12d4d98..3682e97ce 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -91,6 +91,8 @@ namespace MWMechanics virtual void setPlayerClass (const ESM::Class& class_); ///< Set player class to custom class. + virtual void restoreDynamicStats(MWWorld::Ptr actor, bool sleep); + virtual void rest(bool sleep); ///< If the player is sleeping or waiting, this should be called every hour. /// @param sleep is the player sleeping or waiting? diff --git a/apps/openmw/mwworld/cells.cpp b/apps/openmw/mwworld/cells.cpp index 5cac12b9c..8506cefa3 100644 --- a/apps/openmw/mwworld/cells.cpp +++ b/apps/openmw/mwworld/cells.cpp @@ -151,6 +151,19 @@ MWWorld::CellStore *MWWorld::Cells::getInterior (const std::string& name) return &result->second; } +void MWWorld::Cells::rest () +{ + for (auto &interior : mInteriors) + { + interior.second.rest(); + } + + for (auto &exterior : mExteriors) + { + exterior.second.rest(); + } +} + MWWorld::CellStore *MWWorld::Cells::getCell (const ESM::CellId& id) { if (id.mPaged) diff --git a/apps/openmw/mwworld/cells.hpp b/apps/openmw/mwworld/cells.hpp index 0b7d9444f..bd730329b 100644 --- a/apps/openmw/mwworld/cells.hpp +++ b/apps/openmw/mwworld/cells.hpp @@ -61,6 +61,7 @@ namespace MWWorld /// @note name must be lower case Ptr getPtr (const std::string& name); + void rest (); /// Get all Ptrs referencing \a name in exterior cells /// @note Due to the current implementation of getPtr this only supports one Ptr per cell. diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 05ff1e326..5cd8346a7 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -17,6 +17,7 @@ #include #include "../mwbase/environment.hpp" +#include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/world.hpp" #include "../mwmechanics/creaturestats.hpp" @@ -954,6 +955,29 @@ namespace MWWorld } } + void CellStore::rest() + { + if (mState == State_Loaded) + { + for (CellRefList::List::iterator it (mCreatures.mList.begin()); it!=mCreatures.mList.end(); ++it) + { + Ptr ptr = getCurrentPtr(&*it); + if (!ptr.isEmpty() && ptr.getRefData().getCount() > 0) + { + MWBase::Environment::get().getMechanicsManager()->restoreDynamicStats(ptr, true); + } + } + for (CellRefList::List::iterator it (mNpcs.mList.begin()); it!=mNpcs.mList.end(); ++it) + { + Ptr ptr = getCurrentPtr(&*it); + if (!ptr.isEmpty() && ptr.getRefData().getCount() > 0) + { + MWBase::Environment::get().getMechanicsManager()->restoreDynamicStats(ptr, true); + } + } + } + } + void CellStore::respawn() { if (mState == State_Loaded) diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index dd54bdd6a..bcf4b4ada 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -183,6 +183,8 @@ namespace MWWorld /// @return updated MWWorld::Ptr with the new CellStore pointer set. MWWorld::Ptr moveTo(const MWWorld::Ptr& object, MWWorld::CellStore* cellToMoveTo); + void rest(); + /// Make a copy of the given object and insert it into this cell. /// @note If you get a linker error here, this means the given type can not be inserted into a cell. /// The supported types are defined at the bottom of this file. diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 9b701d17b..fe311f8fc 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -3118,6 +3118,10 @@ namespace MWWorld return closestMarker; } + void World::rest() + { + mCells.rest(); + } void World::teleportToClosestMarker (const MWWorld::Ptr& ptr, const std::string& id) diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index e694d9d84..7df8d1af5 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -552,11 +552,9 @@ namespace MWWorld void enableActorCollision(const MWWorld::Ptr& actor, bool enable) override; RestPermitted canRest() const override; - ///< check if the player is allowed to rest \n - /// 0 - yes \n - /// 1 - only waiting \n - /// 2 - player is underwater \n - /// 3 - enemies are nearby (not implemented) + ///< check if the player is allowed to rest + + void rest() override; /// \todo Probably shouldn't be here MWRender::Animation* getAnimation(const MWWorld::Ptr &ptr) override;