#include "spellicons.hpp" #include #include #include #include #include #include #include #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwworld/class.hpp" #include "../mwworld/esmstore.hpp" #include "../mwmechanics/actorutil.hpp" #include "../mwmechanics/creaturestats.hpp" #include "tooltips.hpp" namespace MWGui { void SpellIcons::updateWidgets(MyGUI::Widget* parent, bool adjustSize) { MWWorld::Ptr player = MWMechanics::getPlayer(); const MWMechanics::CreatureStats& stats = player.getClass().getCreatureStats(player); std::map> effects; for (const auto& params : stats.getActiveSpells()) { 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(newEffectSource); } } int w = 2; const auto& store = MWBase::Environment::get().getESMStore(); for (const auto& [effectId, effectInfos] : effects) { const ESM::MagicEffect* effect = store->get().find(effectId); 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) { 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; } if (remainingDuration > 0.f) { MyGUI::ImageBox* image; if (mWidgetMap.find(effectId) == mWidgetMap.end()) { image = parent->createWidget( "ImageBox", MyGUI::IntCoord(w, 2, 16, 16), MyGUI::Align::Default); mWidgetMap[effectId] = image; image->setImageTexture(Misc::ResourceHelpers::correctIconPath( effect->mIcon, MWBase::Environment::get().getResourceSystem()->getVFS())); const std::string& name = ESM::MagicEffect::indexToGmstString(effectId); ToolTipInfo tooltipInfo; tooltipInfo.caption = "#{" + name + "}"; tooltipInfo.icon = effect->mIcon; tooltipInfo.imageSize = 16; tooltipInfo.wordWrap = false; image->setUserData(tooltipInfo); image->setUserString("ToolTipType", "ToolTipInfo"); } else image = mWidgetMap[effectId]; image->setPosition(w, 2); image->setVisible(true); w += 16; ToolTipInfo* tooltipInfo = image->getUserData(); tooltipInfo->text = sourcesDescription; // 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 (adjustSize) { int s = w + 2; if (effects.empty()) s = 0; int diff = parent->getWidth() - s; parent->setSize(s, 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); } } }