diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 8631834c92..2f45d4fe7a 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -41,7 +41,7 @@ add_openmw_dir (mwgui itemmodel containeritemmodel inventoryitemmodel sortfilteritemmodel itemview tradeitemmodel companionitemmodel pickpocketitemmodel controllers savegamedialog recharge mode videowidget backgroundimage itemwidget screenfader debugwindow spellmodel spellview - draganddrop timeadvancer jailscreen itemchargeview keyboardnavigation textcolours + draganddrop timeadvancer jailscreen itemchargeview keyboardnavigation textcolours statswatcher ) add_openmw_dir (mwdialogue diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index c9ce43e013..b6ce4d0619 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -67,10 +67,6 @@ namespace MWBase virtual void drop (const MWWorld::CellStore *cellStore) = 0; ///< Deregister all objects in the given cell. - virtual void watchActor (const MWWorld::Ptr& ptr) = 0; - ///< On each update look for changes in a previously registered actor and update the - /// GUI accordingly. - virtual void update (float duration, bool paused) = 0; ///< Update objects /// diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index d6afe92435..f35df78817 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -154,27 +154,11 @@ namespace MWBase virtual void setConsoleSelectedObject(const MWWorld::Ptr& object) = 0; - /// Set value for the given ID. - virtual void setValue (const std::string& id, const MWMechanics::AttributeValue& value) = 0; - virtual void setValue (int parSkill, const MWMechanics::SkillValue& value) = 0; - virtual void setValue (const std::string& id, const MWMechanics::DynamicStat& value) = 0; - virtual void setValue (const std::string& id, const std::string& value) = 0; - virtual void setValue (const std::string& id, int value) = 0; - /// Set time left for the player to start drowning (update the drowning bar) /// @param time time left to start drowning /// @param maxTime how long we can be underwater (in total) until drowning starts virtual void setDrowningTimeLeft (float time, float maxTime) = 0; - virtual void setPlayerClass (const ESM::Class &class_) = 0; - ///< set current class of player - - virtual void configureSkills (const SkillList& major, const SkillList& minor) = 0; - ///< configure skill groups, each set contains the skill ID for that group. - - virtual void updateSkillArea() = 0; - ///< update display of skills, factions, birth sign, reputation and bounty - virtual void changeCell(const MWWorld::CellStore* cell) = 0; ///< change the active cell @@ -359,6 +343,9 @@ namespace MWBase virtual void windowResized(int x, int y) = 0; virtual void windowClosed() = 0; virtual bool isWindowVisible() = 0; + + virtual void watchActor(const MWWorld::Ptr& ptr) = 0; + virtual MWWorld::Ptr getWatchedActor() const = 0; }; } diff --git a/apps/openmw/mwgui/charactercreation.cpp b/apps/openmw/mwgui/charactercreation.cpp index 54e1a69a49..31fe3afb04 100644 --- a/apps/openmw/mwgui/charactercreation.cpp +++ b/apps/openmw/mwgui/charactercreation.cpp @@ -368,7 +368,6 @@ namespace MWGui if (klass) { mPlayerClass = *klass; - MWBase::Environment::get().getWindowManager()->setPlayerClass(mPlayerClass); } MWBase::Environment::get().getWindowManager()->removeDialog(mPickClassDialog); mPickClassDialog = 0; @@ -422,7 +421,6 @@ namespace MWGui if (mNameDialog) { mPlayerName = mNameDialog->getTextInput(); - MWBase::Environment::get().getWindowManager()->setValue("name", mPlayerName); MWBase::Environment::get().getMechanicsManager()->setPlayerName(mPlayerName); MWBase::Environment::get().getWindowManager()->removeDialog(mNameDialog); mNameDialog = 0; @@ -525,7 +523,6 @@ namespace MWGui MWBase::Environment::get().getMechanicsManager()->setPlayerClass(klass); mPlayerClass = klass; - MWBase::Environment::get().getWindowManager()->setPlayerClass(klass); // Do not delete dialog, so that choices are remembered in case we want to go back and adjust them later mCreateClassDialog->setVisible(false); @@ -722,7 +719,6 @@ namespace MWGui MWBase::Environment::get().getWorld()->getStore().get().find(mGenerateClass); mPlayerClass = *klass; - MWBase::Environment::get().getWindowManager()->setPlayerClass(mPlayerClass); updatePlayerHealth(); } diff --git a/apps/openmw/mwgui/charactercreation.hpp b/apps/openmw/mwgui/charactercreation.hpp index 4f62967858..beb8715fcd 100644 --- a/apps/openmw/mwgui/charactercreation.hpp +++ b/apps/openmw/mwgui/charactercreation.hpp @@ -1,13 +1,12 @@ #ifndef CHARACTER_CREATION_HPP #define CHARACTER_CREATION_HPP -#include #include #include #include -#include "../mwmechanics/stat.hpp" +#include "statswatcher.hpp" namespace osg { @@ -35,21 +34,21 @@ namespace MWGui class ReviewDialog; class MessageBoxManager; - class CharacterCreation + class CharacterCreation : public StatsListener { public: typedef std::vector SkillList; CharacterCreation(osg::Group* parent, Resource::ResourceSystem* resourceSystem); - ~CharacterCreation(); + virtual ~CharacterCreation(); //Show a dialog void spawnDialog(const char id); - void setValue (const std::string& id, const MWMechanics::AttributeValue& value); - void setValue (const std::string& id, const MWMechanics::DynamicStat& value); - void setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::SkillValue& value); - void configureSkills (const SkillList& major, const SkillList& minor); + void setValue (const std::string& id, const MWMechanics::AttributeValue& value) override; + void setValue (const std::string& id, const MWMechanics::DynamicStat& value) override; + void setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::SkillValue& value) override; + void configureSkills(const SkillList& major, const SkillList& minor) override; void onFrame(float duration); diff --git a/apps/openmw/mwgui/hud.hpp b/apps/openmw/mwgui/hud.hpp index c33c4efad8..c28dbc6d7b 100644 --- a/apps/openmw/mwgui/hud.hpp +++ b/apps/openmw/mwgui/hud.hpp @@ -2,8 +2,7 @@ #define OPENMW_GAME_MWGUI_HUD_H #include "mapwindow.hpp" - -#include "../mwmechanics/stat.hpp" +#include "statswatcher.hpp" namespace MWWorld { @@ -17,12 +16,12 @@ namespace MWGui class ItemWidget; class SpellWidget; - class HUD : public WindowBase, public LocalMapBase + class HUD : public WindowBase, public LocalMapBase, public StatsListener { public: HUD(CustomMarkerCollection& customMarkers, DragAndDrop* dragAndDrop, MWRender::LocalMap* localMapRender); virtual ~HUD(); - void setValue (const std::string& id, const MWMechanics::DynamicStat& value); + void setValue (const std::string& id, const MWMechanics::DynamicStat& value) override; /// Set time left for the player to start drowning /// @param time time left to start drowning diff --git a/apps/openmw/mwgui/statswatcher.cpp b/apps/openmw/mwgui/statswatcher.cpp new file mode 100644 index 0000000000..7baec2f2c9 --- /dev/null +++ b/apps/openmw/mwgui/statswatcher.cpp @@ -0,0 +1,209 @@ +#include "statswatcher.hpp" + +#include "../mwbase/environment.hpp" +#include "../mwbase/windowmanager.hpp" +#include "../mwbase/world.hpp" + +#include "../mwmechanics/npcstats.hpp" +#include "../mwmechanics/spellutil.hpp" + +#include "../mwworld/class.hpp" +#include "../mwworld/esmstore.hpp" +#include "../mwworld/inventorystore.hpp" + +namespace MWGui +{ + // mWatchedTimeToStartDrowning = -1 for correct drowning state check, + // if stats.getTimeToStartDrowning() == 0 already on game start + StatsWatcher::StatsWatcher() + : mWatchedLevel(-1), mWatchedTimeToStartDrowning(-1), mWatchedStatsEmpty(true) + { + } + + void StatsWatcher::watchActor(const MWWorld::Ptr& ptr) + { + mWatched = ptr; + } + + void StatsWatcher::update() + { + if (mWatched.isEmpty()) + return; + + MWBase::WindowManager *winMgr = MWBase::Environment::get().getWindowManager(); + const MWMechanics::NpcStats &stats = mWatched.getClass().getNpcStats(mWatched); + for (int i = 0;i < ESM::Attribute::Length;++i) + { + if (stats.getAttribute(i) != mWatchedAttributes[i] || mWatchedStatsEmpty) + { + std::stringstream attrname; + attrname << "AttribVal"<<(i+1); + + mWatchedAttributes[i] = stats.getAttribute(i); + setValue(attrname.str(), stats.getAttribute(i)); + } + } + + if (stats.getHealth() != mWatchedHealth || mWatchedStatsEmpty) + { + static const std::string hbar("HBar"); + mWatchedHealth = stats.getHealth(); + setValue(hbar, stats.getHealth()); + } + if (stats.getMagicka() != mWatchedMagicka || mWatchedStatsEmpty) + { + static const std::string mbar("MBar"); + mWatchedMagicka = stats.getMagicka(); + setValue(mbar, stats.getMagicka()); + } + if (stats.getFatigue() != mWatchedFatigue || mWatchedStatsEmpty) + { + static const std::string fbar("FBar"); + mWatchedFatigue = stats.getFatigue(); + setValue(fbar, stats.getFatigue()); + } + + float timeToDrown = stats.getTimeToStartDrowning(); + + if (timeToDrown != mWatchedTimeToStartDrowning) + { + static const float fHoldBreathTime = MWBase::Environment::get().getWorld()->getStore().get() + .find("fHoldBreathTime")->mValue.getFloat(); + + mWatchedTimeToStartDrowning = timeToDrown; + + if(timeToDrown >= fHoldBreathTime || timeToDrown == -1.0) // -1.0 is a special value during initialization + winMgr->setDrowningBarVisibility(false); + else + { + winMgr->setDrowningBarVisibility(true); + winMgr->setDrowningTimeLeft(stats.getTimeToStartDrowning(), fHoldBreathTime); + } + } + + //Loop over ESM::Skill::SkillEnum + for (int i = 0; i < ESM::Skill::Length; ++i) + { + if(stats.getSkill(i) != mWatchedSkills[i] || mWatchedStatsEmpty) + { + mWatchedSkills[i] = stats.getSkill(i); + setValue((ESM::Skill::SkillEnum)i, stats.getSkill(i)); + } + } + + if (stats.getLevel() != mWatchedLevel || mWatchedStatsEmpty) + { + mWatchedLevel = stats.getLevel(); + setValue("level", mWatchedLevel); + } + + if (mWatched.getClass().isNpc()) + { + const ESM::NPC *watchedRecord = mWatched.get()->mBase; + + if (watchedRecord->mName != mWatchedName || mWatchedStatsEmpty) + { + mWatchedName = watchedRecord->mName; + setValue("name", watchedRecord->mName); + } + + if (watchedRecord->mRace != mWatchedRace || mWatchedStatsEmpty) + { + mWatchedRace = watchedRecord->mRace; + const ESM::Race *race = MWBase::Environment::get().getWorld()->getStore() + .get().find(watchedRecord->mRace); + setValue("race", race->mName); + } + + if (watchedRecord->mClass != mWatchedClass || mWatchedStatsEmpty) + { + mWatchedClass = watchedRecord->mClass; + const ESM::Class *cls = MWBase::Environment::get().getWorld()->getStore() + .get().find(watchedRecord->mClass); + setValue("class", cls->mName); + + MWBase::WindowManager::SkillList majorSkills (5); + MWBase::WindowManager::SkillList minorSkills (5); + + for (int i=0; i<5; ++i) + { + minorSkills[i] = cls->mData.mSkills[i][0]; + majorSkills[i] = cls->mData.mSkills[i][1]; + } + + configureSkills(majorSkills, minorSkills); + } + } + + mWatchedStatsEmpty = false; + + // Update the equipped weapon icon + MWWorld::InventoryStore& inv = mWatched.getClass().getInventoryStore(mWatched); + MWWorld::ContainerStoreIterator weapon = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); + if (weapon == inv.end()) + winMgr->unsetSelectedWeapon(); + else + winMgr->setSelectedWeapon(*weapon); + + // Update the selected spell icon + MWWorld::ContainerStoreIterator enchantItem = inv.getSelectedEnchantItem(); + if (enchantItem != inv.end()) + winMgr->setSelectedEnchantItem(*enchantItem); + else + { + const std::string& spell = winMgr->getSelectedSpell(); + if (!spell.empty()) + winMgr->setSelectedSpell(spell, int(MWMechanics::getSpellSuccessChance(spell, mWatched))); + else + winMgr->unsetSelectedSpell(); + } + } + + void StatsWatcher::addListener(StatsListener* listener) + { + mListeners.insert(listener); + } + + void StatsWatcher::removeListener(StatsListener* listener) + { + mListeners.erase(listener); + } + + void StatsWatcher::setValue(const std::string& id, const MWMechanics::AttributeValue& value) + { + for (StatsListener* listener : mListeners) + listener->setValue(id, value); + } + + void StatsWatcher::setValue(ESM::Skill::SkillEnum parSkill, const MWMechanics::SkillValue& value) + { + /// \todo Don't use the skill enum as a parameter type (we will have to drop it anyway, once we + /// allow custom skills. + for (StatsListener* listener : mListeners) + listener->setValue(parSkill, value); + } + + void StatsWatcher::setValue(const std::string& id, const MWMechanics::DynamicStat& value) + { + for (StatsListener* listener : mListeners) + listener->setValue(id, value); + } + + void StatsWatcher::setValue(const std::string& id, const std::string& value) + { + for (StatsListener* listener : mListeners) + listener->setValue(id, value); + } + + void StatsWatcher::setValue(const std::string& id, int value) + { + for (StatsListener* listener : mListeners) + listener->setValue(id, value); + } + + void StatsWatcher::configureSkills(const std::vector& major, const std::vector& minor) + { + for (StatsListener* listener : mListeners) + listener->configureSkills(major, minor); + } +} diff --git a/apps/openmw/mwgui/statswatcher.hpp b/apps/openmw/mwgui/statswatcher.hpp new file mode 100644 index 0000000000..9f17e5c54b --- /dev/null +++ b/apps/openmw/mwgui/statswatcher.hpp @@ -0,0 +1,69 @@ +#ifndef MWGUI_STATSWATCHER_H +#define MWGUI_STATSWATCHER_H + +#include + +#include +#include + +#include "../mwmechanics/stat.hpp" + +#include "../mwworld/ptr.hpp" + +namespace MWGui +{ + class StatsListener + { + public: + /// Set value for the given ID. + virtual void setValue(const std::string& id, const MWMechanics::AttributeValue& value) {} + virtual void setValue(const std::string& id, const MWMechanics::DynamicStat& value) {} + virtual void setValue(const std::string& id, const std::string& value) {} + virtual void setValue(const std::string& id, int value) {} + virtual void setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::SkillValue& value) {} + virtual void configureSkills(const std::vector& major, const std::vector& minor) {} + }; + + class StatsWatcher + { + MWWorld::Ptr mWatched; + + MWMechanics::AttributeValue mWatchedAttributes[ESM::Attribute::Length]; + MWMechanics::SkillValue mWatchedSkills[ESM::Skill::Length]; + + MWMechanics::DynamicStat mWatchedHealth; + MWMechanics::DynamicStat mWatchedMagicka; + MWMechanics::DynamicStat mWatchedFatigue; + + std::string mWatchedName; + std::string mWatchedRace; + std::string mWatchedClass; + + int mWatchedLevel; + + float mWatchedTimeToStartDrowning; + + bool mWatchedStatsEmpty; + + std::set mListeners; + + void setValue(const std::string& id, const MWMechanics::AttributeValue& value); + void setValue(const std::string& id, const MWMechanics::DynamicStat& value); + void setValue(const std::string& id, const std::string& value); + void setValue(const std::string& id, int value); + void setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::SkillValue& value); + void configureSkills(const std::vector& major, const std::vector& minor); + + public: + StatsWatcher(); + + void update(); + void addListener(StatsListener* listener); + void removeListener(StatsListener* listener); + + void watchActor(const MWWorld::Ptr& ptr); + virtual MWWorld::Ptr getWatchedActor() const { return mWatched; } + }; +} + +#endif diff --git a/apps/openmw/mwgui/statswindow.hpp b/apps/openmw/mwgui/statswindow.hpp index 7d1be6a155..60e17a821c 100644 --- a/apps/openmw/mwgui/statswindow.hpp +++ b/apps/openmw/mwgui/statswindow.hpp @@ -1,16 +1,14 @@ #ifndef MWGUI_STATS_WINDOW_H #define MWGUI_STATS_WINDOW_H -#include "../mwmechanics/stat.hpp" +#include "statswatcher.hpp" #include "windowpinnablebase.hpp" -#include - namespace MWGui { class WindowManager; - class StatsWindow : public WindowPinnableBase, public NoDrop + class StatsWindow : public WindowPinnableBase, public NoDrop, public StatsListener { public: typedef std::map FactionList; @@ -26,13 +24,13 @@ namespace MWGui void setPlayerName(const std::string& playerName); /// Set value for the given ID. - void setValue (const std::string& id, const MWMechanics::AttributeValue& value); - void setValue (const std::string& id, const MWMechanics::DynamicStat& value); - void setValue (const std::string& id, const std::string& value); - void setValue (const std::string& id, int value); - void setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::SkillValue& value); + void setValue (const std::string& id, const MWMechanics::AttributeValue& value) override; + void setValue (const std::string& id, const MWMechanics::DynamicStat& value) override; + void setValue (const std::string& id, const std::string& value) override; + void setValue (const std::string& id, int value) override; + void setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::SkillValue& value) override; + void configureSkills(const SkillList& major, const SkillList& minor) override; - void configureSkills (const SkillList& major, const SkillList& minor); void setReputation (int reputation) { if (reputation != mReputation) mChanged = true; this->mReputation = reputation; } void setBounty (int bounty) { if (bounty != mBounty) mChanged = true; this->mBounty = bounty; } void updateSkillArea(); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index e1f7a4fbf3..8f83c165ae 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -272,6 +272,8 @@ namespace MWGui mVideoWrapper = new SDLUtil::VideoWrapper(window, viewer); mVideoWrapper->setGammaContrast(Settings::Manager::getFloat("gamma", "Video"), Settings::Manager::getFloat("contrast", "Video")); + + mStatsWatcher.reset(new StatsWatcher()); } void WindowManager::loadUserFonts() @@ -466,6 +468,10 @@ namespace MWGui // Set up visibility updateVisible(); + + mStatsWatcher->addListener(mHud); + mStatsWatcher->addListener(mStatsWindow); + mStatsWatcher->addListener(mCharGen); } int WindowManager::getFontHeight() const @@ -478,8 +484,11 @@ namespace MWGui if (newgame) { disallowAll(); + + mStatsWatcher->removeListener(mCharGen); delete mCharGen; mCharGen = new CharacterCreation(mViewer->getSceneData()->asGroup(), mResourceSystem); + mStatsWatcher->addListener(mCharGen); } else allow(GW_ALL); @@ -489,6 +498,8 @@ namespace MWGui { try { + mStatsWatcher.reset(); + mKeyboardNavigation.reset(); MyGUI::LanguageManager::getInstance().eventRequestTag.clear(); @@ -649,58 +660,11 @@ namespace MWGui } } - void WindowManager::setValue (const std::string& id, const MWMechanics::AttributeValue& value) - { - mStatsWindow->setValue (id, value); - mCharGen->setValue(id, value); - } - - void WindowManager::setValue (int parSkill, const MWMechanics::SkillValue& value) - { - /// \todo Don't use the skill enum as a parameter type (we will have to drop it anyway, once we - /// allow custom skills. - mStatsWindow->setValue(static_cast (parSkill), value); - mCharGen->setValue(static_cast (parSkill), value); - } - - void WindowManager::setValue (const std::string& id, const MWMechanics::DynamicStat& value) - { - mStatsWindow->setValue (id, value); - mHud->setValue (id, value); - mCharGen->setValue(id, value); - } - - void WindowManager::setValue (const std::string& id, const std::string& value) - { - mStatsWindow->setValue (id, value); - } - - void WindowManager::setValue (const std::string& id, int value) - { - mStatsWindow->setValue (id, value); - } - void WindowManager::setDrowningTimeLeft (float time, float maxTime) { mHud->setDrowningTimeLeft(time, maxTime); } - void WindowManager::setPlayerClass (const ESM::Class &class_) - { - mStatsWindow->setValue("class", class_.mName); - } - - void WindowManager::configureSkills (const SkillList& major, const SkillList& minor) - { - mStatsWindow->configureSkills (major, minor); - mCharGen->configureSkills(major, minor); - } - - void WindowManager::updateSkillArea() - { - mStatsWindow->updateSkillArea(); - } - void WindowManager::removeDialog(Layout*dialog) { if (!dialog) @@ -904,7 +868,9 @@ namespace MWGui if (mCharGen) mCharGen->onFrame(frameDuration); - updateActivatedQuickKey (); + updateActivatedQuickKey(); + + mStatsWatcher->update(); cleanupGarbage(); } @@ -2210,4 +2176,14 @@ namespace MWGui for (unsigned int i=0; isetVisible(visible); } + + void WindowManager::watchActor(const MWWorld::Ptr& ptr) + { + mStatsWatcher->watchActor(ptr); + } + + MWWorld::Ptr WindowManager::getWatchedActor() const + { + return mStatsWatcher->getWatchedActor(); + } } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 42750705d1..a8cb0b10ab 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -13,13 +13,12 @@ #include "../mwbase/windowmanager.hpp" -#include "../mwworld/ptr.hpp" - #include #include #include #include "mapwindow.hpp" +#include "statswatcher.hpp" #include "textcolours.hpp" #include @@ -195,22 +194,11 @@ namespace MWGui virtual void setConsoleSelectedObject(const MWWorld::Ptr& object); - ///< Set value for the given ID. - virtual void setValue (const std::string& id, const MWMechanics::AttributeValue& value); - virtual void setValue (int parSkill, const MWMechanics::SkillValue& value); - virtual void setValue (const std::string& id, const MWMechanics::DynamicStat& value); - virtual void setValue (const std::string& id, const std::string& value); - virtual void setValue (const std::string& id, int value); - /// Set time left for the player to start drowning (update the drowning bar) /// @param time time left to start drowning /// @param maxTime how long we can be underwater (in total) until drowning starts virtual void setDrowningTimeLeft (float time, float maxTime); - virtual void setPlayerClass (const ESM::Class &class_); ///< set current class of player - virtual void configureSkills (const SkillList& major, const SkillList& minor); ///< configure skill groups, each set contains the skill ID for that group. - virtual void updateSkillArea(); ///< update display of skills, factions, birth sign, reputation and bounty - virtual void changeCell(const MWWorld::CellStore* cell); ///< change the active cell virtual void setFocusObject(const MWWorld::Ptr& focus); @@ -298,6 +286,9 @@ namespace MWGui virtual void windowClosed(); virtual bool isWindowVisible(); + virtual void watchActor(const MWWorld::Ptr& ptr); + virtual MWWorld::Ptr getWatchedActor() const; + virtual void executeInConsole (const std::string& path); virtual void enableRest() { mRestAllowed = true; } @@ -400,6 +391,7 @@ namespace MWGui osgViewer::Viewer* mViewer; std::unique_ptr mFontLoader; + std::unique_ptr mStatsWatcher; bool mConsoleOnlyScripts; diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index d7da4ebb72..fcae60c584 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -236,10 +236,8 @@ namespace MWMechanics invStore.autoEquip(ptr); } - // mWatchedTimeToStartDrowning = -1 for correct drowning state check, - // if stats.getTimeToStartDrowning() == 0 already on game start MechanicsManager::MechanicsManager() - : mWatchedLevel(-1), mWatchedTimeToStartDrowning(-1), mWatchedStatsEmpty (true), mUpdatePlayer (true), mClassSelected (false), + : mUpdatePlayer (true), mClassSelected (false), mRaceSelected (false), mAI(true) { //buildPlayer no longer here, needs to be done explicitly after all subsystems are up and running @@ -261,16 +259,16 @@ namespace MWMechanics void MechanicsManager::remove(const MWWorld::Ptr& ptr) { - if(ptr == mWatched) - mWatched = MWWorld::Ptr(); + if(ptr == MWBase::Environment::get().getWindowManager()->getWatchedActor()) + MWBase::Environment::get().getWindowManager()->watchActor(MWWorld::Ptr()); mActors.removeActor(ptr); mObjects.removeObject(ptr); } void MechanicsManager::updateCell(const MWWorld::Ptr &old, const MWWorld::Ptr &ptr) { - if(old == mWatched) - mWatched = ptr; + if(old == MWBase::Environment::get().getWindowManager()->getWatchedActor()) + MWBase::Environment::get().getWindowManager()->watchActor(ptr); if(ptr.getClass().isActor()) mActors.updateActor(old, ptr); @@ -278,19 +276,12 @@ namespace MWMechanics mObjects.updateObject(old, ptr); } - void MechanicsManager::drop(const MWWorld::CellStore *cellStore) { - mActors.dropActors(cellStore, mWatched); + mActors.dropActors(cellStore, getPlayer()); mObjects.dropObjects(cellStore); } - - void MechanicsManager::watchActor(const MWWorld::Ptr& ptr) - { - mWatched = ptr; - } - void MechanicsManager::restoreStatsAfterCorprus(const MWWorld::Ptr& actor, const std::string& sourceId) { auto& stats = actor.getClass().getCreatureStats (actor); @@ -311,133 +302,10 @@ namespace MWMechanics void MechanicsManager::update(float duration, bool paused) { - if(!mWatched.isEmpty()) - { - MWBase::WindowManager *winMgr = MWBase::Environment::get().getWindowManager(); - const MWMechanics::NpcStats &stats = mWatched.getClass().getNpcStats(mWatched); - for(int i = 0;i < ESM::Attribute::Length;++i) - { - if(stats.getAttribute(i) != mWatchedAttributes[i] || mWatchedStatsEmpty) - { - std::stringstream attrname; - attrname << "AttribVal"<<(i+1); - - mWatchedAttributes[i] = stats.getAttribute(i); - winMgr->setValue(attrname.str(), stats.getAttribute(i)); - } - } - - if(stats.getHealth() != mWatchedHealth || mWatchedStatsEmpty) - { - static const std::string hbar("HBar"); - mWatchedHealth = stats.getHealth(); - winMgr->setValue(hbar, stats.getHealth()); - } - if(stats.getMagicka() != mWatchedMagicka || mWatchedStatsEmpty) - { - static const std::string mbar("MBar"); - mWatchedMagicka = stats.getMagicka(); - winMgr->setValue(mbar, stats.getMagicka()); - } - if(stats.getFatigue() != mWatchedFatigue || mWatchedStatsEmpty) - { - static const std::string fbar("FBar"); - mWatchedFatigue = stats.getFatigue(); - winMgr->setValue(fbar, stats.getFatigue()); - } - - float timeToDrown = stats.getTimeToStartDrowning(); - - if(timeToDrown != mWatchedTimeToStartDrowning) - { - static const float fHoldBreathTime = MWBase::Environment::get().getWorld()->getStore().get() - .find("fHoldBreathTime")->mValue.getFloat(); - - mWatchedTimeToStartDrowning = timeToDrown; - - if(timeToDrown >= fHoldBreathTime || timeToDrown == -1.0) // -1.0 is a special value during initialization - winMgr->setDrowningBarVisibility(false); - else - { - winMgr->setDrowningBarVisibility(true); - winMgr->setDrowningTimeLeft(stats.getTimeToStartDrowning(), fHoldBreathTime); - } - } - - //Loop over ESM::Skill::SkillEnum - for(int i = 0; i < ESM::Skill::Length; ++i) - { - if(stats.getSkill(i) != mWatchedSkills[i] || mWatchedStatsEmpty) - { - mWatchedSkills[i] = stats.getSkill(i); - winMgr->setValue((ESM::Skill::SkillEnum)i, stats.getSkill(i)); - } - } - - if(stats.getLevel() != mWatchedLevel) - { - mWatchedLevel = stats.getLevel(); - winMgr->setValue("level", mWatchedLevel); - } - - mWatchedStatsEmpty = false; - - // Update the equipped weapon icon - MWWorld::InventoryStore& inv = mWatched.getClass().getInventoryStore(mWatched); - MWWorld::ContainerStoreIterator weapon = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); - if (weapon == inv.end()) - winMgr->unsetSelectedWeapon(); - else - winMgr->setSelectedWeapon(*weapon); - - // Update the selected spell icon - MWWorld::ContainerStoreIterator enchantItem = inv.getSelectedEnchantItem(); - if (enchantItem != inv.end()) - winMgr->setSelectedEnchantItem(*enchantItem); - else - { - const std::string& spell = winMgr->getSelectedSpell(); - if (!spell.empty()) - winMgr->setSelectedSpell(spell, int(getSpellSuccessChance(spell, mWatched))); - else - winMgr->unsetSelectedSpell(); - } - - } - if (mUpdatePlayer) { - MWBase::World *world = MWBase::Environment::get().getWorld(); - - // basic player profile; should not change anymore after the creation phase is finished. - MWBase::WindowManager *winMgr = - MWBase::Environment::get().getWindowManager(); - - const ESM::NPC *player = - world->getPlayerPtr().get()->mBase; - - const ESM::Race *race = - world->getStore().get().find(player->mRace); - const ESM::Class *cls = - world->getStore().get().find(player->mClass); - - winMgr->setValue ("name", player->mName); - winMgr->setValue ("race", race->mName); - winMgr->setValue ("class", cls->mName); - mUpdatePlayer = false; - MWBase::WindowManager::SkillList majorSkills (5); - MWBase::WindowManager::SkillList minorSkills (5); - - for (int i=0; i<5; ++i) - { - minorSkills[i] = cls->mData.mSkills[i][0]; - majorSkills[i] = cls->mData.mSkills[i][1]; - } - - winMgr->configureSkills (majorSkills, minorSkills); - // HACK? The player has been changed, so a new Animation object may // have been made for them. Make sure they're properly updated. MWWorld::Ptr ptr = getPlayer(); @@ -517,7 +385,7 @@ namespace MWMechanics int MechanicsManager::getHoursToRest() const { - return mActors.getHoursToRest(mWatched); + return mActors.getHoursToRest(getPlayer()); } void MechanicsManager::setPlayerName (const std::string& name) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index 86bc4c720b..c546497bb8 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -21,20 +21,6 @@ namespace MWMechanics { class MechanicsManager : public MWBase::MechanicsManager { - MWWorld::Ptr mWatched; - - AttributeValue mWatchedAttributes[8]; - SkillValue mWatchedSkills[27]; - - DynamicStat mWatchedHealth; - DynamicStat mWatchedMagicka; - DynamicStat mWatchedFatigue; - - int mWatchedLevel; - - float mWatchedTimeToStartDrowning; - - bool mWatchedStatsEmpty; bool mUpdatePlayer; bool mClassSelected; bool mRaceSelected; @@ -68,10 +54,6 @@ namespace MWMechanics virtual void drop(const MWWorld::CellStore *cellStore) override; ///< Deregister all objects in the given cell. - virtual void watchActor(const MWWorld::Ptr& ptr) override; - ///< On each update look for changes in a previously registered actor and update the - /// GUI accordingly. - virtual void update (float duration, bool paused) override; ///< Update objects /// diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 42fe1a960c..1138483946 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -741,15 +741,12 @@ namespace MWWorld player.getClass().adjustPosition(player, true); } - MWBase::MechanicsManager *mechMgr = - MWBase::Environment::get().getMechanicsManager(); - - mechMgr->updateCell(old, player); - mechMgr->watchActor(player); + MWBase::Environment::get().getMechanicsManager()->updateCell(old, player); + MWBase::Environment::get().getWindowManager()->watchActor(player); mPhysics->updatePtr(old, player); - MWBase::Environment::get().getWorld()->adjustSky(); + world->adjustSky(); mLastPlayerPos = player.getRefData().getPosition().asVec3(); } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 6788a7fa29..d8b8222427 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2453,7 +2453,7 @@ namespace MWWorld rotateObject(player, 0.f, 0.f, 0.f, MWBase::RotationFlag_inverseOrder | MWBase::RotationFlag_adjust); MWBase::Environment::get().getMechanicsManager()->add(getPlayerPtr()); - MWBase::Environment::get().getMechanicsManager()->watchActor(getPlayerPtr()); + MWBase::Environment::get().getWindowManager()->watchActor(getPlayerPtr()); std::string model = getPlayerPtr().getClass().getModel(getPlayerPtr()); model = Misc::ResourceHelpers::correctActorModelPath(model, mResourceSystem->getVFS());