1 #include "levelupdialog.hpp"
2 
3 #include <MyGUI_Button.h>
4 #include <MyGUI_ImageBox.h>
5 #include <MyGUI_EditBox.h>
6 
7 #include <components/fallback/fallback.hpp>
8 
9 #include "../mwbase/windowmanager.hpp"
10 #include "../mwbase/environment.hpp"
11 #include "../mwbase/world.hpp"
12 #include "../mwbase/soundmanager.hpp"
13 
14 #include "../mwworld/class.hpp"
15 
16 #include "../mwmechanics/creaturestats.hpp"
17 #include "../mwmechanics/npcstats.hpp"
18 #include "../mwmechanics/actorutil.hpp"
19 
20 #include "class.hpp"
21 
22 namespace MWGui
23 {
24     const unsigned int LevelupDialog::sMaxCoins = 3;
LevelupDialog()25     LevelupDialog::LevelupDialog()
26         : WindowBase("openmw_levelup_dialog.layout"),
27           mCoinCount(sMaxCoins)
28     {
29         getWidget(mOkButton, "OkButton");
30         getWidget(mClassImage, "ClassImage");
31         getWidget(mLevelText, "LevelText");
32         getWidget(mLevelDescription, "LevelDescription");
33         getWidget(mCoinBox, "Coins");
34         getWidget(mAssignWidget, "AssignWidget");
35 
36         mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &LevelupDialog::onOkButtonClicked);
37 
38         for (int i=1; i<9; ++i)
39         {
40             MyGUI::TextBox* t;
41             getWidget(t, "AttribVal" + MyGUI::utility::toString(i));
42             mAttributeValues.push_back(t);
43 
44             MyGUI::Button* b;
45             getWidget(b, "Attrib" + MyGUI::utility::toString(i));
46             b->setUserData (i-1);
47             b->eventMouseButtonClick += MyGUI::newDelegate(this, &LevelupDialog::onAttributeClicked);
48             mAttributes.push_back(b);
49 
50             getWidget(t, "AttribMultiplier" + MyGUI::utility::toString(i));
51             mAttributeMultipliers.push_back(t);
52         }
53 
54         for (unsigned int i = 0; i < mCoinCount; ++i)
55         {
56             MyGUI::ImageBox* image = mCoinBox->createWidget<MyGUI::ImageBox>("ImageBox", MyGUI::IntCoord(0,0,16,16), MyGUI::Align::Default);
57             image->setImageTexture ("icons\\tx_goldicon.dds");
58             mCoins.push_back(image);
59         }
60 
61         center();
62     }
63 
setAttributeValues()64     void LevelupDialog::setAttributeValues()
65     {
66         MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayerPtr();
67         MWMechanics::CreatureStats& creatureStats = player.getClass().getCreatureStats(player);
68         MWMechanics::NpcStats& pcStats = player.getClass().getNpcStats (player);
69 
70         for (int i = 0; i < 8; ++i)
71         {
72             int val = creatureStats.getAttribute(i).getBase();
73             if (std::find(mSpentAttributes.begin(), mSpentAttributes.end(), i) != mSpentAttributes.end())
74             {
75                 val += pcStats.getLevelupAttributeMultiplier(i);
76             }
77 
78             if (val >= 100)
79                 val = 100;
80 
81             mAttributeValues[i]->setCaption(MyGUI::utility::toString(val));
82         }
83     }
84 
85 
resetCoins()86     void LevelupDialog::resetCoins()
87     {
88         const int coinSpacing = 33;
89         int curX = mCoinBox->getWidth()/2 - (coinSpacing*(mCoinCount - 1) + 16*mCoinCount)/2;
90         for (unsigned int i=0; i<sMaxCoins; ++i)
91         {
92             MyGUI::ImageBox* image = mCoins[i];
93             image->detachFromWidget();
94             image->attachToWidget(mCoinBox);
95             if (i < mCoinCount)
96             {
97                 mCoins[i]->setVisible(true);
98                 image->setCoord(MyGUI::IntCoord(curX,0,16,16));
99                 curX += 16+coinSpacing;
100             }
101             else
102                 mCoins[i]->setVisible(false);
103         }
104     }
105 
assignCoins()106     void LevelupDialog::assignCoins()
107     {
108         resetCoins();
109         for (unsigned int i=0; i<mSpentAttributes.size(); ++i)
110         {
111             MyGUI::ImageBox* image = mCoins[i];
112             image->detachFromWidget();
113             image->attachToWidget(mAssignWidget);
114 
115             int attribute = mSpentAttributes[i];
116 
117             int xdiff = mAttributeMultipliers[attribute]->getCaption() == "" ? 0 : 20;
118 
119             MyGUI::IntPoint pos = mAttributes[attribute]->getAbsolutePosition() - mAssignWidget->getAbsolutePosition() - MyGUI::IntPoint(22+xdiff,0);
120             pos.top += (mAttributes[attribute]->getHeight() - image->getHeight())/2;
121             image->setPosition(pos);
122         }
123 
124         setAttributeValues();
125     }
126 
onOpen()127     void LevelupDialog::onOpen()
128     {
129         MWBase::World *world = MWBase::Environment::get().getWorld();
130         MWWorld::Ptr player = world->getPlayerPtr();
131         MWMechanics::CreatureStats& creatureStats = player.getClass().getCreatureStats(player);
132         MWMechanics::NpcStats& pcStats = player.getClass().getNpcStats(player);
133 
134         setClassImage(mClassImage, getLevelupClassImage(pcStats.getSkillIncreasesForSpecialization(0),
135                                                         pcStats.getSkillIncreasesForSpecialization(1),
136                                                         pcStats.getSkillIncreasesForSpecialization(2)));
137 
138         int level = creatureStats.getLevel ()+1;
139         mLevelText->setCaptionWithReplacing("#{sLevelUpMenu1} " + MyGUI::utility::toString(level));
140 
141         std::string levelupdescription;
142         levelupdescription = Fallback::Map::getString("Level_Up_Level"+MyGUI::utility::toString(level));
143 
144         if (levelupdescription == "")
145             levelupdescription = Fallback::Map::getString("Level_Up_Default");
146 
147         mLevelDescription->setCaption (levelupdescription);
148 
149         unsigned int availableAttributes = 0;
150         for (int i = 0; i < 8; ++i)
151         {
152             MyGUI::TextBox* text = mAttributeMultipliers[i];
153             if (pcStats.getAttribute(i).getBase() < 100)
154             {
155                 mAttributes[i]->setEnabled(true);
156                 mAttributeValues[i]->setEnabled(true);
157                 availableAttributes++;
158 
159                 float mult = pcStats.getLevelupAttributeMultiplier (i);
160                 mult = std::min(mult, 100-pcStats.getAttribute(i).getBase());
161                 text->setCaption(mult <= 1 ? "" : "x" + MyGUI::utility::toString(mult));
162             }
163             else
164             {
165                 mAttributes[i]->setEnabled(false);
166                 mAttributeValues[i]->setEnabled(false);
167 
168                 text->setCaption("");
169             }
170         }
171 
172         mCoinCount = std::min(sMaxCoins, availableAttributes);
173 
174         mSpentAttributes.clear();
175         resetCoins();
176 
177         setAttributeValues();
178 
179         center();
180 
181         // Play LevelUp Music
182         MWBase::Environment::get().getSoundManager()->streamMusic("Special/MW_Triumph.mp3");
183     }
184 
onOkButtonClicked(MyGUI::Widget * sender)185     void LevelupDialog::onOkButtonClicked(MyGUI::Widget* sender)
186     {
187         MWWorld::Ptr player = MWMechanics::getPlayer();
188         MWMechanics::NpcStats& pcStats = player.getClass().getNpcStats (player);
189 
190         if (mSpentAttributes.size() < mCoinCount)
191             MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage36}");
192         else
193         {
194             // increase attributes
195             for (unsigned int i = 0; i < mCoinCount; ++i)
196             {
197                 MWMechanics::AttributeValue attribute = pcStats.getAttribute(mSpentAttributes[i]);
198                 attribute.setBase(attribute.getBase() + pcStats.getLevelupAttributeMultiplier(mSpentAttributes[i]));
199 
200                 if (attribute.getBase() >= 100)
201                     attribute.setBase(100);
202                 pcStats.setAttribute(mSpentAttributes[i], attribute);
203             }
204 
205             pcStats.levelUp();
206 
207             MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Levelup);
208         }
209 
210     }
211 
onAttributeClicked(MyGUI::Widget * sender)212     void LevelupDialog::onAttributeClicked(MyGUI::Widget *sender)
213     {
214         int attribute = *sender->getUserData<int>();
215 
216         std::vector<int>::iterator found = std::find(mSpentAttributes.begin(), mSpentAttributes.end(), attribute);
217         if (found != mSpentAttributes.end())
218             mSpentAttributes.erase(found);
219         else
220         {
221             if (mSpentAttributes.size() == mCoinCount)
222                 mSpentAttributes[mCoinCount - 1] = attribute;
223             else
224                 mSpentAttributes.push_back(attribute);
225         }
226         assignCoins();
227     }
228 
getLevelupClassImage(const int combatIncreases,const int magicIncreases,const int stealthIncreases)229     std::string LevelupDialog::getLevelupClassImage(const int combatIncreases, const int magicIncreases, const int stealthIncreases)
230     {
231         std::string ret = "acrobat";
232 
233         int total = combatIncreases + magicIncreases + stealthIncreases;
234         if (total == 0)
235             return ret;
236 
237         int combatFraction = static_cast<int>(static_cast<float>(combatIncreases) / total * 10.f);
238         int magicFraction = static_cast<int>(static_cast<float>(magicIncreases) / total * 10.f);
239         int stealthFraction = static_cast<int>(static_cast<float>(stealthIncreases) / total * 10.f);
240 
241         if (combatFraction > 7)
242             ret = "warrior";
243         else if (magicFraction > 7)
244             ret = "mage";
245         else if (stealthFraction > 7)
246             ret = "thief";
247 
248         switch (combatFraction)
249         {
250             case 7:
251                 ret = "warrior";
252                 break;
253             case 6:
254                 if (stealthFraction == 1)
255                     ret = "barbarian";
256                 else if (stealthFraction == 3)
257                     ret = "crusader";
258                 else
259                     ret = "knight";
260                 break;
261             case 5:
262                 if (stealthFraction == 3)
263                     ret = "scout";
264                 else
265                     ret = "archer";
266                 break;
267             case 4:
268                 ret = "rogue";
269                 break;
270             default:
271                 break;
272         }
273 
274         switch (magicFraction)
275         {
276             case 7:
277                 ret = "mage";
278                 break;
279             case 6:
280                 if (combatFraction == 2)
281                     ret = "sorcerer";
282                 else if (combatIncreases == 3)
283                     ret = "healer";
284                 else
285                     ret = "battlemage";
286                 break;
287             case 5:
288                 ret = "witchhunter";
289                 break;
290             case 4:
291                 ret = "spellsword";
292                 // In vanilla there's also code for "nightblade", however it seems to be unreachable.
293                 break;
294             default:
295                 break;
296         }
297 
298         switch (stealthFraction)
299         {
300             case 7:
301                 ret = "thief";
302                 break;
303             case 6:
304                 if (magicFraction == 1)
305                     ret = "agent";
306                 else if (magicIncreases == 3)
307                     ret = "assassin";
308                 else
309                     ret = "acrobat";
310                 break;
311             case 5:
312                 if (magicIncreases == 3)
313                     ret = "monk";
314                 else
315                     ret = "pilgrim";
316                 break;
317             case 3:
318                 if (magicFraction == 3)
319                     ret = "bard";
320                 break;
321             default:
322                 break;
323         }
324 
325         return ret;
326     }
327 }
328