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