1 #include "misc.hpp"
2 
3 #include <components/esm/loadmisc.hpp>
4 #include <components/settings/settings.hpp>
5 
6 #include "../mwbase/environment.hpp"
7 #include "../mwbase/world.hpp"
8 #include "../mwbase/windowmanager.hpp"
9 
10 #include "../mwworld/cellstore.hpp"
11 #include "../mwworld/esmstore.hpp"
12 #include "../mwphysics/physicssystem.hpp"
13 #include "../mwworld/manualref.hpp"
14 #include "../mwworld/nullaction.hpp"
15 #include "../mwworld/actionsoulgem.hpp"
16 
17 #include "../mwgui/tooltips.hpp"
18 
19 #include "../mwrender/objects.hpp"
20 #include "../mwrender/renderinginterface.hpp"
21 
22 namespace MWClass
23 {
isGold(const MWWorld::ConstPtr & ptr) const24     bool Miscellaneous::isGold (const MWWorld::ConstPtr& ptr) const
25     {
26         return Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_001")
27                         || Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_005")
28                         || Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_010")
29                         || Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_025")
30                         || Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_100");
31     }
32 
insertObjectRendering(const MWWorld::Ptr & ptr,const std::string & model,MWRender::RenderingInterface & renderingInterface) const33     void Miscellaneous::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const
34     {
35         if (!model.empty()) {
36             renderingInterface.getObjects().insertModel(ptr, model);
37         }
38     }
39 
insertObject(const MWWorld::Ptr & ptr,const std::string & model,MWPhysics::PhysicsSystem & physics) const40     void Miscellaneous::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const
41     {
42         // TODO: add option somewhere to enable collision for placeable objects
43     }
44 
getModel(const MWWorld::ConstPtr & ptr) const45     std::string Miscellaneous::getModel(const MWWorld::ConstPtr &ptr) const
46     {
47         const MWWorld::LiveCellRef<ESM::Miscellaneous> *ref = ptr.get<ESM::Miscellaneous>();
48 
49         const std::string &model = ref->mBase->mModel;
50         if (!model.empty()) {
51             return "meshes\\" + model;
52         }
53         return "";
54     }
55 
getName(const MWWorld::ConstPtr & ptr) const56     std::string Miscellaneous::getName (const MWWorld::ConstPtr& ptr) const
57     {
58         const MWWorld::LiveCellRef<ESM::Miscellaneous> *ref = ptr.get<ESM::Miscellaneous>();
59         const std::string& name = ref->mBase->mName;
60 
61         return !name.empty() ? name : ref->mBase->mId;
62     }
63 
activate(const MWWorld::Ptr & ptr,const MWWorld::Ptr & actor) const64     std::shared_ptr<MWWorld::Action> Miscellaneous::activate (const MWWorld::Ptr& ptr,
65         const MWWorld::Ptr& actor) const
66     {
67         return defaultItemActivate(ptr, actor);
68     }
69 
getScript(const MWWorld::ConstPtr & ptr) const70     std::string Miscellaneous::getScript (const MWWorld::ConstPtr& ptr) const
71     {
72         const MWWorld::LiveCellRef<ESM::Miscellaneous> *ref = ptr.get<ESM::Miscellaneous>();
73 
74         return ref->mBase->mScript;
75     }
76 
getValue(const MWWorld::ConstPtr & ptr) const77     int Miscellaneous::getValue (const MWWorld::ConstPtr& ptr) const
78     {
79         const MWWorld::LiveCellRef<ESM::Miscellaneous> *ref = ptr.get<ESM::Miscellaneous>();
80 
81         int value = ref->mBase->mData.mValue;
82         if (ptr.getCellRef().getGoldValue() > 1 && ptr.getRefData().getCount() == 1)
83             value = ptr.getCellRef().getGoldValue();
84 
85         if (ptr.getCellRef().getSoul() != "")
86         {
87             const ESM::Creature *creature = MWBase::Environment::get().getWorld()->getStore().get<ESM::Creature>().search(ref->mRef.getSoul());
88             if (creature)
89             {
90                 int soul = creature->mData.mSoul;
91                 if (Settings::Manager::getBool("rebalance soul gem values", "Game"))
92                 {
93                     // use the 'soul gem value rebalance' formula from the Morrowind Code Patch
94                     float soulValue = 0.0001 * pow(soul, 3) + 2 * soul;
95 
96                     // for Azura's star add the unfilled value
97                     if (Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "Misc_SoulGem_Azura"))
98                         value += soulValue;
99                     else
100                         value = soulValue;
101                 }
102                 else
103                     value *= soul;
104             }
105         }
106 
107         return value;
108     }
109 
registerSelf()110     void Miscellaneous::registerSelf()
111     {
112         std::shared_ptr<Class> instance (new Miscellaneous);
113 
114         registerClass (typeid (ESM::Miscellaneous).name(), instance);
115     }
116 
getUpSoundId(const MWWorld::ConstPtr & ptr) const117     std::string Miscellaneous::getUpSoundId (const MWWorld::ConstPtr& ptr) const
118     {
119         if (isGold(ptr))
120             return std::string("Item Gold Up");
121         return std::string("Item Misc Up");
122     }
123 
getDownSoundId(const MWWorld::ConstPtr & ptr) const124     std::string Miscellaneous::getDownSoundId (const MWWorld::ConstPtr& ptr) const
125     {
126         if (isGold(ptr))
127             return std::string("Item Gold Down");
128         return std::string("Item Misc Down");
129     }
130 
getInventoryIcon(const MWWorld::ConstPtr & ptr) const131     std::string Miscellaneous::getInventoryIcon (const MWWorld::ConstPtr& ptr) const
132     {
133         const MWWorld::LiveCellRef<ESM::Miscellaneous> *ref = ptr.get<ESM::Miscellaneous>();
134 
135         return ref->mBase->mIcon;
136     }
137 
getToolTipInfo(const MWWorld::ConstPtr & ptr,int count) const138     MWGui::ToolTipInfo Miscellaneous::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const
139     {
140         const MWWorld::LiveCellRef<ESM::Miscellaneous> *ref = ptr.get<ESM::Miscellaneous>();
141 
142         MWGui::ToolTipInfo info;
143 
144         bool gold = isGold(ptr);
145         if (gold)
146             count *= getValue(ptr);
147 
148         std::string countString;
149         if (!gold)
150             countString = MWGui::ToolTips::getCountString(count);
151         else // gold displays its count also if it's 1.
152             countString = " (" + std::to_string(count) + ")";
153 
154         info.caption = MyGUI::TextIterator::toTagsString(getName(ptr)) + countString + MWGui::ToolTips::getSoulString(ptr.getCellRef());
155         info.icon = ref->mBase->mIcon;
156 
157         std::string text;
158 
159         text += MWGui::ToolTips::getWeightString(ref->mBase->mData.mWeight, "#{sWeight}");
160         if (!gold && !ref->mBase->mData.mIsKey)
161             text += MWGui::ToolTips::getValueString(getValue(ptr), "#{sValue}");
162 
163         if (MWBase::Environment::get().getWindowManager()->getFullHelp()) {
164             text += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
165             text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script");
166         }
167 
168         info.text = text;
169 
170         return info;
171     }
172 
copyToCell(const MWWorld::ConstPtr & ptr,MWWorld::CellStore & cell,int count) const173     MWWorld::Ptr Miscellaneous::copyToCell(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell, int count) const
174     {
175         MWWorld::Ptr newPtr;
176 
177         const MWWorld::ESMStore &store =
178             MWBase::Environment::get().getWorld()->getStore();
179 
180         if (isGold(ptr)) {
181             int goldAmount = getValue(ptr) * count;
182 
183             std::string base = "Gold_001";
184             if (goldAmount >= 100)
185                 base = "Gold_100";
186             else if (goldAmount >= 25)
187                 base = "Gold_025";
188             else if (goldAmount >= 10)
189                 base = "Gold_010";
190             else if (goldAmount >= 5)
191                 base = "Gold_005";
192 
193             // Really, I have no idea why moving ref out of conditional
194             // scope causes list::push_back throwing std::bad_alloc
195             MWWorld::ManualRef newRef(store, base);
196             const MWWorld::LiveCellRef<ESM::Miscellaneous> *ref =
197                 newRef.getPtr().get<ESM::Miscellaneous>();
198 
199             newPtr = MWWorld::Ptr(cell.insert(ref), &cell);
200             newPtr.getCellRef().setGoldValue(goldAmount);
201             newPtr.getRefData().setCount(1);
202         } else {
203             const MWWorld::LiveCellRef<ESM::Miscellaneous> *ref =
204                 ptr.get<ESM::Miscellaneous>();
205             newPtr = MWWorld::Ptr(cell.insert(ref), &cell);
206             newPtr.getRefData().setCount(count);
207         }
208         newPtr.getCellRef().unsetRefNum();
209 
210         return newPtr;
211     }
212 
use(const MWWorld::Ptr & ptr,bool force) const213     std::shared_ptr<MWWorld::Action> Miscellaneous::use (const MWWorld::Ptr& ptr, bool force) const
214     {
215         if (ptr.getCellRef().getSoul().empty() || !MWBase::Environment::get().getWorld()->getStore().get<ESM::Creature>().search(ptr.getCellRef().getSoul()))
216             return std::shared_ptr<MWWorld::Action>(new MWWorld::NullAction());
217         else
218             return std::shared_ptr<MWWorld::Action>(new MWWorld::ActionSoulgem(ptr));
219     }
220 
canSell(const MWWorld::ConstPtr & item,int npcServices) const221     bool Miscellaneous::canSell (const MWWorld::ConstPtr& item, int npcServices) const
222     {
223         const MWWorld::LiveCellRef<ESM::Miscellaneous> *ref = item.get<ESM::Miscellaneous>();
224 
225         return !ref->mBase->mData.mIsKey && (npcServices & ESM::NPC::Misc) && !isGold(item);
226     }
227 
getWeight(const MWWorld::ConstPtr & ptr) const228     float Miscellaneous::getWeight(const MWWorld::ConstPtr &ptr) const
229     {
230         const MWWorld::LiveCellRef<ESM::Miscellaneous> *ref = ptr.get<ESM::Miscellaneous>();
231         return ref->mBase->mData.mWeight;
232     }
233 
isKey(const MWWorld::ConstPtr & ptr) const234     bool Miscellaneous::isKey(const MWWorld::ConstPtr &ptr) const
235     {
236         const MWWorld::LiveCellRef<ESM::Miscellaneous> *ref = ptr.get<ESM::Miscellaneous>();
237         return ref->mBase->mData.mIsKey != 0;
238     }
239 
240 }
241