#include "statswatcher.hpp" #include #include #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwmechanics/npcstats.hpp" #include "../mwworld/class.hpp" #include "../mwworld/esmstore.hpp" #include 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; const auto& store = MWBase::Environment::get().getESMStore(); MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager(); const MWMechanics::NpcStats& stats = mWatched.getClass().getNpcStats(mWatched); for (const ESM::Attribute& attribute : store->get()) { const auto& value = stats.getAttribute(attribute.mId); if (value != mWatchedAttributes[attribute.mId] || mWatchedStatsEmpty) { mWatchedAttributes[attribute.mId] = value; setAttribute(attribute.mId, value); } } if (stats.getHealth() != mWatchedHealth || mWatchedStatsEmpty) { mWatchedHealth = stats.getHealth(); setValue("HBar", stats.getHealth()); } if (stats.getMagicka() != mWatchedMagicka || mWatchedStatsEmpty) { mWatchedMagicka = stats.getMagicka(); setValue("MBar", stats.getMagicka()); } if (stats.getFatigue() != mWatchedFatigue || mWatchedStatsEmpty) { mWatchedFatigue = stats.getFatigue(); setValue("FBar", stats.getFatigue()); } float timeToDrown = stats.getTimeToStartDrowning(); if (timeToDrown != mWatchedTimeToStartDrowning) { static const float fHoldBreathTime = MWBase::Environment::get() .getESMStore() ->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); } } for (const ESM::Skill& skill : store->get()) { const auto& value = stats.getSkill(skill.mId); if (value != mWatchedSkills[skill.mId] || mWatchedStatsEmpty) { mWatchedSkills[skill.mId] = value; setValue(skill.mId, value); } } 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 = store->get().find(watchedRecord->mRace); setValue("race", race->mName); } if (watchedRecord->mClass != mWatchedClass || mWatchedStatsEmpty) { mWatchedClass = watchedRecord->mClass; const ESM::Class* cls = store->get().find(watchedRecord->mClass); setValue("class", cls->mName); size_t size = cls->mData.mSkills.size(); std::vector majorSkills(size); std::vector minorSkills(size); for (size_t i = 0; i < size; ++i) { minorSkills[i] = ESM::Skill::indexToRefId(cls->mData.mSkills[i][0]); majorSkills[i] = ESM::Skill::indexToRefId(cls->mData.mSkills[i][1]); } configureSkills(majorSkills, minorSkills); } } mWatchedStatsEmpty = false; } void StatsWatcher::addListener(StatsListener* listener) { mListeners.insert(listener); } void StatsWatcher::removeListener(StatsListener* listener) { mListeners.erase(listener); } void StatsWatcher::setAttribute(ESM::RefId id, const MWMechanics::AttributeValue& value) { for (StatsListener* listener : mListeners) listener->setAttribute(id, value); } void StatsWatcher::setValue(ESM::RefId id, const MWMechanics::SkillValue& value) { for (StatsListener* listener : mListeners) listener->setValue(id, value); } void StatsWatcher::setValue(std::string_view id, const MWMechanics::DynamicStat& value) { for (StatsListener* listener : mListeners) listener->setValue(id, value); } void StatsWatcher::setValue(std::string_view id, const std::string& value) { for (StatsListener* listener : mListeners) listener->setValue(id, value); } void StatsWatcher::setValue(std::string_view 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); } }