diff --git a/apps/openmw/mwgui/spellicons.cpp b/apps/openmw/mwgui/spellicons.cpp index f3e532346d..cb786e7384 100644 --- a/apps/openmw/mwgui/spellicons.cpp +++ b/apps/openmw/mwgui/spellicons.cpp @@ -1,6 +1,5 @@ #include "spellicons.hpp" -#include #include #include @@ -24,184 +23,139 @@ namespace MWGui { - void SpellIcons::updateWidgets(MyGUI::Widget* parent, bool adjustSize) + namespace { - MWWorld::Ptr player = MWMechanics::getPlayer(); - const MWMechanics::CreatureStats& stats = player.getClass().getCreatureStats(player); - - std::map> effects; - for (const auto& params : stats.getActiveSpells()) + MyGUI::ImageBox* createIcon(MyGUI::Widget& parent, std::string_view name, std::string_view icon, int size) { - for (const auto& effect : params.getEffects()) - { - if (!(effect.mFlags & ESM::ActiveEffect::Flag_Applied)) - continue; - MagicEffectInfo newEffectSource; - newEffectSource.mKey = MWMechanics::EffectKey(effect.mEffectId, effect.getSkillOrAttribute()); - newEffectSource.mMagnitude = static_cast(effect.mMagnitude); - newEffectSource.mPermanent = effect.mDuration == -1.f; - newEffectSource.mRemainingTime = effect.mTimeLeft; - newEffectSource.mSource = params.getDisplayName(); - newEffectSource.mTotalTime = effect.mDuration; - effects[effect.mEffectId].push_back(std::move(newEffectSource)); - } + const VFS::Manager& vfs = *MWBase::Environment::get().getResourceSystem()->getVFS(); + + const MyGUI::IntCoord coord(0, 0, size, size); + MyGUI::ImageBox* widget = parent.createWidget("ImageBox", coord, MyGUI::Align::Default); + widget->setImageTexture(Misc::ResourceHelpers::correctIconPath(VFS::Path::toNormalized(icon), vfs)); + + ToolTipInfo tooltipInfo; + tooltipInfo.caption = name; + tooltipInfo.icon = icon; + tooltipInfo.imageSize = size; + tooltipInfo.wordWrap = false; + + widget->setUserData(tooltipInfo); + widget->setUserString("ToolTipType", "ToolTipInfo"); + widget->setVisible(false); + + return widget; } - int w = 2; - const auto& store = MWBase::Environment::get().getESMStore(); - for (const auto& [effectId, effectInfos] : effects) + std::string printEffectMagnitude(float srcMagnitude, ESM::MagicEffect::MagnitudeDisplayType displayType) { - const ESM::MagicEffect* effect = store->get().find(effectId); + std::string result; + if (displayType == ESM::MagicEffect::MDT_None) + return result; - float remainingDuration = 0; - float totalDuration = 0; - - std::string sourcesDescription; - - static const float fadeTime - = store->get().find("fMagicStartIconBlink")->mValue.getFloat(); - - bool addNewLine = false; - for (const MagicEffectInfo& effectInfo : effectInfos) + const int magnitude = static_cast(srcMagnitude); + if (displayType == ESM::MagicEffect::MDT_TimesInt) { - if (addNewLine) - sourcesDescription += '\n'; - - // if at least one of the effect sources is permanent, the effect will never wear off - if (effectInfo.mPermanent) - { - remainingDuration = fadeTime; - totalDuration = fadeTime; - } - else - { - remainingDuration = std::max(remainingDuration, effectInfo.mRemainingTime); - totalDuration = std::max(totalDuration, effectInfo.mTotalTime); - } - - sourcesDescription += effectInfo.mSource; - - if (effect->mData.mFlags & ESM::MagicEffect::TargetSkill) - { - const ESM::Skill* skill = store->get().find(effectInfo.mKey.mArg); - sourcesDescription += " (" + skill->mName + ')'; - } - if (effect->mData.mFlags & ESM::MagicEffect::TargetAttribute) - { - const ESM::Attribute* attribute = store->get().find(effectInfo.mKey.mArg); - sourcesDescription += " (" + attribute->mName + ')'; - } - ESM::MagicEffect::MagnitudeDisplayType displayType = effect->getMagnitudeDisplayType(); - if (displayType == ESM::MagicEffect::MDT_TimesInt) - { - std::string_view timesInt - = MWBase::Environment::get().getWindowManager()->getGameSettingString("sXTimesINT", {}); - std::stringstream formatter; - formatter << std::fixed << std::setprecision(1) << " " << (effectInfo.mMagnitude / 10.0f) - << timesInt; - sourcesDescription += formatter.str(); - } - else if (displayType != ESM::MagicEffect::MDT_None) - { - sourcesDescription += ": " + MyGUI::utility::toString(effectInfo.mMagnitude); - - if (displayType == ESM::MagicEffect::MDT_Percentage) - sourcesDescription - += MWBase::Environment::get().getWindowManager()->getGameSettingString("spercent", {}); - else if (displayType == ESM::MagicEffect::MDT_Feet) - { - sourcesDescription += ' '; - sourcesDescription - += MWBase::Environment::get().getWindowManager()->getGameSettingString("sfeet", {}); - } - else if (displayType == ESM::MagicEffect::MDT_Level) - { - sourcesDescription += ' '; - if (effectInfo.mMagnitude > 1) - sourcesDescription - += MWBase::Environment::get().getWindowManager()->getGameSettingString("sLevels", {}); - else - sourcesDescription - += MWBase::Environment::get().getWindowManager()->getGameSettingString("sLevel", {}); - } - else // ESM::MagicEffect::MDT_Points - { - sourcesDescription += ' '; - if (effectInfo.mMagnitude > 1) - sourcesDescription - += MWBase::Environment::get().getWindowManager()->getGameSettingString("spoints", {}); - else - sourcesDescription - += MWBase::Environment::get().getWindowManager()->getGameSettingString("spoint", {}); - } - } - if (effectInfo.mRemainingTime > -1 && Settings::game().mShowEffectDuration) - sourcesDescription - += MWGui::ToolTips::getDurationString(effectInfo.mRemainingTime, " #{sDuration}"); - - addNewLine = true; + std::stringstream formatter; + formatter << std::fixed << std::setprecision(1) << " " << (magnitude / 10.0f); + result += formatter.str(); + } + else + { + result += ": " + MyGUI::utility::toString(magnitude); + if (displayType != ESM::MagicEffect::MDT_Percentage) + result += ' '; } - if (remainingDuration > 0.f) + std::string_view unit; + if (displayType == ESM::MagicEffect::MDT_TimesInt) + unit = "sXTimesINT"; + else if (displayType == ESM::MagicEffect::MDT_Percentage) + unit = "sPercent"; + else if (displayType == ESM::MagicEffect::MDT_Feet) + unit = "sFeet"; + else if (displayType == ESM::MagicEffect::MDT_Level) + unit = magnitude > 1 ? "sLevels" : "sLevel"; + else if (displayType == ESM::MagicEffect::MDT_Points) + unit = magnitude > 1 ? "sPoints" : "sPoint"; + + result += MWBase::Environment::get().getWindowManager()->getGameSettingString(unit, {}); + + return result; + } + } + + void SpellIcons::updateWidgets(MyGUI::Widget* parent, bool adjustSize) + { + for (auto& [effectId, widget] : mWidgetMap) + { + widget->setVisible(false); + widget->setAlpha(1.f); + widget->getUserData()->text.clear(); + } + + int horizontalOffset = 2; + constexpr int verticalOffset = 2; + constexpr int size = 16; + + const MWWorld::ESMStore& store = *MWBase::Environment::get().getESMStore(); + static const float fadeTime = store.get().find("fMagicStartIconBlink")->mValue.getFloat(); + + const MWWorld::Ptr player = MWMechanics::getPlayer(); + const MWMechanics::CreatureStats& stats = player.getClass().getCreatureStats(player); + for (const auto& params : stats.getActiveSpells()) + { + for (const auto& source : params.getEffects()) { - MyGUI::ImageBox* image; + if (!(source.mFlags & ESM::ActiveEffect::Flag_Applied)) + continue; + if (source.mDuration != -1.f && source.mTimeLeft <= 0.f) + continue; + + const ESM::RefId effectId = source.mEffectId; + const ESM::MagicEffect& effect = *store.get().find(effectId); + const ESM::RefId arg = source.getSkillOrAttribute(); + if (mWidgetMap.find(effectId) == mWidgetMap.end()) + mWidgetMap[effectId] = createIcon(*parent, effect.mName, effect.mIcon, size); + + MyGUI::ImageBox& widget = *mWidgetMap[effectId]; + if (!widget.getVisible()) { - image = parent->createWidget( - "ImageBox", MyGUI::IntCoord(w, 2, 16, 16), MyGUI::Align::Default); - mWidgetMap[effectId] = image; - - image->setImageTexture( - Misc::ResourceHelpers::correctIconPath(VFS::Path::toNormalized(effect->mIcon), - *MWBase::Environment::get().getResourceSystem()->getVFS())); - - ToolTipInfo tooltipInfo; - tooltipInfo.caption = effect->mName; - tooltipInfo.icon = effect->mIcon; - tooltipInfo.imageSize = 16; - tooltipInfo.wordWrap = false; - - image->setUserData(tooltipInfo); - image->setUserString("ToolTipType", "ToolTipInfo"); + widget.setPosition(horizontalOffset, verticalOffset); + widget.setVisible(true); + if (source.mDuration >= fadeTime && fadeTime > 0.f) + widget.setAlpha(std::min(source.mTimeLeft / fadeTime, 1.f)); + horizontalOffset += size; } - else - image = mWidgetMap[effectId]; - image->setPosition(w, 2); - image->setVisible(true); - w += 16; + std::string& desc = widget.getUserData()->text; + if (!desc.empty()) + desc += '\n'; - ToolTipInfo* tooltipInfo = image->getUserData(); - tooltipInfo->text = std::move(sourcesDescription); + desc += params.getDisplayName(); - // Fade out - if (totalDuration >= fadeTime && fadeTime > 0.f) - image->setAlpha(std::min(remainingDuration / fadeTime, 1.f)); - } - else if (mWidgetMap.find(effectId) != mWidgetMap.end()) - { - MyGUI::ImageBox* image = mWidgetMap[effectId]; - image->setVisible(false); - image->setAlpha(1.f); + if (effect.mData.mFlags & ESM::MagicEffect::TargetSkill) + { + const ESM::Skill& skill = *store.get().find(arg); + desc += " (" + skill.mName + ')'; + } + if (effect.mData.mFlags & ESM::MagicEffect::TargetAttribute) + { + const ESM::Attribute& attribute = *store.get().find(arg); + desc += " (" + attribute.mName + ')'; + } + desc += printEffectMagnitude(source.mMagnitude, effect.getMagnitudeDisplayType()); + if (source.mTimeLeft > -1 && Settings::game().mShowEffectDuration) + desc += MWGui::ToolTips::getDurationString(source.mTimeLeft, " #{sDuration}"); } } if (adjustSize) { - int s = w + 2; - if (effects.empty()) - s = 0; - int diff = parent->getWidth() - s; - parent->setSize(s, parent->getHeight()); + const int newWidth = horizontalOffset > 2 ? horizontalOffset + 2 : 0; + const int diff = parent->getWidth() - newWidth; + parent->setSize(newWidth, parent->getHeight()); parent->setPosition(parent->getLeft() + diff, parent->getTop()); } - - // hide inactive effects - for (auto& widgetPair : mWidgetMap) - { - if (effects.find(widgetPair.first) == effects.end()) - widgetPair.second->setVisible(false); - } } - } diff --git a/apps/openmw/mwgui/spellicons.hpp b/apps/openmw/mwgui/spellicons.hpp index e1d1d169d5..bc274a324f 100644 --- a/apps/openmw/mwgui/spellicons.hpp +++ b/apps/openmw/mwgui/spellicons.hpp @@ -1,43 +1,19 @@ #ifndef MWGUI_SPELLICONS_H #define MWGUI_SPELLICONS_H -#include -#include +#include -#include "../mwmechanics/magiceffects.hpp" +#include namespace MyGUI { class Widget; class ImageBox; } -namespace ESM -{ - struct ENAMstruct; - struct EffectList; -} namespace MWGui { - // information about a single magic effect source as required for display in the tooltip - struct MagicEffectInfo - { - MagicEffectInfo() - : mMagnitude(0) - , mRemainingTime(0.f) - , mTotalTime(0.f) - , mPermanent(false) - { - } - std::string mSource; // display name for effect source (e.g. potion name) - MWMechanics::EffectKey mKey; - int mMagnitude; - float mRemainingTime; - float mTotalTime; - bool mPermanent; // the effect is permanent - }; - class SpellIcons { public: