1 #include "spellicons.hpp" 2 3 #include <sstream> 4 #include <iomanip> 5 6 #include <MyGUI_ImageBox.h> 7 8 #include <components/esm/loadmgef.hpp> 9 #include <components/settings/settings.hpp> 10 11 #include "../mwbase/world.hpp" 12 #include "../mwbase/environment.hpp" 13 #include "../mwbase/windowmanager.hpp" 14 15 #include "../mwworld/class.hpp" 16 #include "../mwworld/esmstore.hpp" 17 #include "../mwworld/inventorystore.hpp" 18 19 #include "../mwmechanics/creaturestats.hpp" 20 #include "../mwmechanics/actorutil.hpp" 21 22 #include "tooltips.hpp" 23 24 25 namespace MWGui 26 { 27 visit(MWMechanics::EffectKey key,int effectIndex,const std::string & sourceName,const std::string & sourceId,int casterActorId,float magnitude,float remainingTime,float totalTime)28 void EffectSourceVisitor::visit (MWMechanics::EffectKey key, int effectIndex, 29 const std::string& sourceName, const std::string& sourceId, int casterActorId, 30 float magnitude, float remainingTime, float totalTime) 31 { 32 MagicEffectInfo newEffectSource; 33 newEffectSource.mKey = key; 34 newEffectSource.mMagnitude = static_cast<int>(magnitude); 35 newEffectSource.mPermanent = mIsPermanent; 36 newEffectSource.mRemainingTime = remainingTime; 37 newEffectSource.mSource = sourceName; 38 newEffectSource.mTotalTime = totalTime; 39 40 mEffectSources[key.mId].push_back(newEffectSource); 41 } 42 43 updateWidgets(MyGUI::Widget * parent,bool adjustSize)44 void SpellIcons::updateWidgets(MyGUI::Widget *parent, bool adjustSize) 45 { 46 // TODO: Tracking add/remove/expire would be better than force updating every frame 47 48 MWWorld::Ptr player = MWMechanics::getPlayer(); 49 const MWMechanics::CreatureStats& stats = player.getClass().getCreatureStats(player); 50 51 52 EffectSourceVisitor visitor; 53 54 // permanent item enchantments & permanent spells 55 visitor.mIsPermanent = true; 56 MWWorld::InventoryStore& store = player.getClass().getInventoryStore(player); 57 store.visitEffectSources(visitor); 58 stats.getSpells().visitEffectSources(visitor); 59 60 // now add lasting effects 61 visitor.mIsPermanent = false; 62 stats.getActiveSpells().visitEffectSources(visitor); 63 64 std::map <int, std::vector<MagicEffectInfo> >& effects = visitor.mEffectSources; 65 66 int w=2; 67 68 for (auto& effectInfoPair : effects) 69 { 70 const int effectId = effectInfoPair.first; 71 const ESM::MagicEffect* effect = 72 MWBase::Environment::get().getWorld ()->getStore ().get<ESM::MagicEffect>().find(effectId); 73 74 float remainingDuration = 0; 75 float totalDuration = 0; 76 77 std::string sourcesDescription; 78 79 static const float fadeTime = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fMagicStartIconBlink")->mValue.getFloat(); 80 81 std::vector<MagicEffectInfo>& effectInfos = effectInfoPair.second; 82 bool addNewLine = false; 83 for (const MagicEffectInfo& effectInfo : effectInfos) 84 { 85 if (addNewLine) 86 sourcesDescription += "\n"; 87 88 // if at least one of the effect sources is permanent, the effect will never wear off 89 if (effectInfo.mPermanent) 90 { 91 remainingDuration = fadeTime; 92 totalDuration = fadeTime; 93 } 94 else 95 { 96 remainingDuration = std::max(remainingDuration, effectInfo.mRemainingTime); 97 totalDuration = std::max(totalDuration, effectInfo.mTotalTime); 98 } 99 100 sourcesDescription += effectInfo.mSource; 101 102 if (effect->mData.mFlags & ESM::MagicEffect::TargetSkill) 103 sourcesDescription += " (" + 104 MWBase::Environment::get().getWindowManager()->getGameSettingString( 105 ESM::Skill::sSkillNameIds[effectInfo.mKey.mArg], "") + ")"; 106 if (effect->mData.mFlags & ESM::MagicEffect::TargetAttribute) 107 sourcesDescription += " (" + 108 MWBase::Environment::get().getWindowManager()->getGameSettingString( 109 ESM::Attribute::sGmstAttributeIds[effectInfo.mKey.mArg], "") + ")"; 110 111 ESM::MagicEffect::MagnitudeDisplayType displayType = effect->getMagnitudeDisplayType(); 112 if (displayType == ESM::MagicEffect::MDT_TimesInt) 113 { 114 std::string timesInt = MWBase::Environment::get().getWindowManager()->getGameSettingString("sXTimesINT", ""); 115 std::stringstream formatter; 116 formatter << std::fixed << std::setprecision(1) << " " << (effectInfo.mMagnitude / 10.0f) << timesInt; 117 sourcesDescription += formatter.str(); 118 } 119 else if ( displayType != ESM::MagicEffect::MDT_None ) 120 { 121 sourcesDescription += ": " + MyGUI::utility::toString(effectInfo.mMagnitude); 122 123 if ( displayType == ESM::MagicEffect::MDT_Percentage ) 124 sourcesDescription += MWBase::Environment::get().getWindowManager()->getGameSettingString("spercent", ""); 125 else if ( displayType == ESM::MagicEffect::MDT_Feet ) 126 sourcesDescription += " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("sfeet", ""); 127 else if ( displayType == ESM::MagicEffect::MDT_Level ) 128 { 129 sourcesDescription += " " + ((effectInfo.mMagnitude > 1) ? 130 MWBase::Environment::get().getWindowManager()->getGameSettingString("sLevels", "") : 131 MWBase::Environment::get().getWindowManager()->getGameSettingString("sLevel", "") ); 132 } 133 else // ESM::MagicEffect::MDT_Points 134 { 135 sourcesDescription += " " + ((effectInfo.mMagnitude > 1) ? 136 MWBase::Environment::get().getWindowManager()->getGameSettingString("spoints", "") : 137 MWBase::Environment::get().getWindowManager()->getGameSettingString("spoint", "") ); 138 } 139 } 140 if (effectInfo.mRemainingTime > -1 && Settings::Manager::getBool("show effect duration","Game")) 141 sourcesDescription += MWGui::ToolTips::getDurationString(effectInfo.mRemainingTime, " #{sDuration}"); 142 143 addNewLine = true; 144 } 145 146 if (remainingDuration > 0.f) 147 { 148 MyGUI::ImageBox* image; 149 if (mWidgetMap.find(effectId) == mWidgetMap.end()) 150 { 151 image = parent->createWidget<MyGUI::ImageBox> 152 ("ImageBox", MyGUI::IntCoord(w,2,16,16), MyGUI::Align::Default); 153 mWidgetMap[effectId] = image; 154 155 image->setImageTexture(MWBase::Environment::get().getWindowManager()->correctIconPath(effect->mIcon)); 156 157 std::string name = ESM::MagicEffect::effectIdToString (effectId); 158 159 ToolTipInfo tooltipInfo; 160 tooltipInfo.caption = "#{" + name + "}"; 161 tooltipInfo.icon = effect->mIcon; 162 tooltipInfo.imageSize = 16; 163 tooltipInfo.wordWrap = false; 164 165 image->setUserData(tooltipInfo); 166 image->setUserString("ToolTipType", "ToolTipInfo"); 167 } 168 else 169 image = mWidgetMap[effectId]; 170 171 image->setPosition(w,2); 172 image->setVisible(true); 173 w += 16; 174 175 ToolTipInfo* tooltipInfo = image->getUserData<ToolTipInfo>(); 176 tooltipInfo->text = sourcesDescription; 177 178 // Fade out 179 if (totalDuration >= fadeTime && fadeTime > 0.f) 180 image->setAlpha(std::min(remainingDuration/fadeTime, 1.f)); 181 } 182 else if (mWidgetMap.find(effectId) != mWidgetMap.end()) 183 { 184 MyGUI::ImageBox* image = mWidgetMap[effectId]; 185 image->setVisible(false); 186 image->setAlpha(1.f); 187 } 188 } 189 190 if (adjustSize) 191 { 192 int s = w + 2; 193 if (effects.empty()) 194 s = 0; 195 int diff = parent->getWidth() - s; 196 parent->setSize(s, parent->getHeight()); 197 parent->setPosition(parent->getLeft()+diff, parent->getTop()); 198 } 199 200 // hide inactive effects 201 for (auto& widgetPair : mWidgetMap) 202 { 203 if (effects.find(widgetPair.first) == effects.end()) 204 widgetPair.second->setVisible(false); 205 } 206 } 207 208 } 209