1 #include "activator.hpp"
2 
3 #include <components/esm/loadacti.hpp>
4 #include <components/misc/rng.hpp>
5 #include <components/sceneutil/positionattitudetransform.hpp>
6 
7 #include "../mwbase/environment.hpp"
8 #include "../mwbase/windowmanager.hpp"
9 #include "../mwbase/world.hpp"
10 
11 #include "../mwworld/cellstore.hpp"
12 #include "../mwworld/esmstore.hpp"
13 #include "../mwworld/ptr.hpp"
14 #include "../mwworld/action.hpp"
15 #include "../mwworld/failedaction.hpp"
16 #include "../mwworld/nullaction.hpp"
17 
18 #include "../mwphysics/physicssystem.hpp"
19 
20 #include "../mwrender/objects.hpp"
21 #include "../mwrender/renderinginterface.hpp"
22 #include "../mwrender/vismask.hpp"
23 
24 #include "../mwgui/tooltips.hpp"
25 
26 #include "../mwmechanics/npcstats.hpp"
27 
28 
29 namespace MWClass
30 {
31 
insertObjectRendering(const MWWorld::Ptr & ptr,const std::string & model,MWRender::RenderingInterface & renderingInterface) const32     void Activator::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const
33     {
34         if (!model.empty())
35         {
36             renderingInterface.getObjects().insertModel(ptr, model, true);
37             ptr.getRefData().getBaseNode()->setNodeMask(MWRender::Mask_Static);
38         }
39     }
40 
insertObject(const MWWorld::Ptr & ptr,const std::string & model,MWPhysics::PhysicsSystem & physics) const41     void Activator::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const
42     {
43         if(!model.empty())
44             physics.addObject(ptr, model);
45     }
46 
getModel(const MWWorld::ConstPtr & ptr) const47     std::string Activator::getModel(const MWWorld::ConstPtr &ptr) const
48     {
49         const MWWorld::LiveCellRef<ESM::Activator> *ref = ptr.get<ESM::Activator>();
50 
51         const std::string &model = ref->mBase->mModel;
52         if (!model.empty()) {
53             return "meshes\\" + model;
54         }
55         return "";
56     }
57 
isActivator() const58     bool Activator::isActivator() const
59     {
60         return true;
61     }
62 
useAnim() const63     bool Activator::useAnim() const
64     {
65         return true;
66     }
67 
getName(const MWWorld::ConstPtr & ptr) const68     std::string Activator::getName (const MWWorld::ConstPtr& ptr) const
69     {
70         const MWWorld::LiveCellRef<ESM::Activator> *ref = ptr.get<ESM::Activator>();
71 
72         return ref->mBase->mName;
73     }
74 
getScript(const MWWorld::ConstPtr & ptr) const75     std::string Activator::getScript (const MWWorld::ConstPtr& ptr) const
76     {
77         const MWWorld::LiveCellRef<ESM::Activator> *ref =
78             ptr.get<ESM::Activator>();
79 
80         return ref->mBase->mScript;
81     }
82 
registerSelf()83     void Activator::registerSelf()
84     {
85         std::shared_ptr<Class> instance (new Activator);
86 
87         registerClass (typeid (ESM::Activator).name(), instance);
88     }
89 
hasToolTip(const MWWorld::ConstPtr & ptr) const90     bool Activator::hasToolTip (const MWWorld::ConstPtr& ptr) const
91     {
92         return !getName(ptr).empty();
93     }
94 
allowTelekinesis(const MWWorld::ConstPtr & ptr) const95     bool Activator::allowTelekinesis(const MWWorld::ConstPtr &ptr) const {
96         return false;
97     }
98 
getToolTipInfo(const MWWorld::ConstPtr & ptr,int count) const99     MWGui::ToolTipInfo Activator::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const
100     {
101         const MWWorld::LiveCellRef<ESM::Activator> *ref = ptr.get<ESM::Activator>();
102 
103         MWGui::ToolTipInfo info;
104         info.caption = MyGUI::TextIterator::toTagsString(getName(ptr)) + MWGui::ToolTips::getCountString(count);
105 
106         std::string text;
107         if (MWBase::Environment::get().getWindowManager()->getFullHelp())
108         {
109             text += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
110             text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script");
111         }
112         info.text = text;
113 
114         return info;
115     }
116 
activate(const MWWorld::Ptr & ptr,const MWWorld::Ptr & actor) const117     std::shared_ptr<MWWorld::Action> Activator::activate(const MWWorld::Ptr &ptr, const MWWorld::Ptr &actor) const
118     {
119         if(actor.getClass().isNpc() && actor.getClass().getNpcStats(actor).isWerewolf())
120         {
121             const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore();
122             const ESM::Sound *sound = store.get<ESM::Sound>().searchRandom("WolfActivator");
123 
124             std::shared_ptr<MWWorld::Action> action(new MWWorld::FailedAction("#{sWerewolfRefusal}"));
125             if(sound) action->setSound(sound->mId);
126 
127             return action;
128         }
129         return std::shared_ptr<MWWorld::Action>(new MWWorld::NullAction);
130     }
131 
132 
copyToCellImpl(const MWWorld::ConstPtr & ptr,MWWorld::CellStore & cell) const133     MWWorld::Ptr Activator::copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const
134     {
135         const MWWorld::LiveCellRef<ESM::Activator> *ref = ptr.get<ESM::Activator>();
136 
137         return MWWorld::Ptr(cell.insert(ref), &cell);
138     }
139 
getSoundIdFromSndGen(const MWWorld::Ptr & ptr,const std::string & name) const140     std::string Activator::getSoundIdFromSndGen(const MWWorld::Ptr &ptr, const std::string &name) const
141     {
142         const std::string model = getModel(ptr); // Assume it's not empty, since we wouldn't have gotten the soundgen otherwise
143         const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore();
144         std::string creatureId;
145 
146         for (const ESM::Creature &iter : store.get<ESM::Creature>())
147         {
148             if (!iter.mModel.empty() && Misc::StringUtils::ciEqual(model, "meshes\\" + iter.mModel))
149             {
150                 creatureId = !iter.mOriginal.empty() ? iter.mOriginal : iter.mId;
151                 break;
152             }
153         }
154 
155         int type = getSndGenTypeFromName(name);
156 
157         std::vector<const ESM::SoundGenerator*> fallbacksounds;
158         if (!creatureId.empty())
159         {
160             std::vector<const ESM::SoundGenerator*> sounds;
161             for (auto sound = store.get<ESM::SoundGenerator>().begin(); sound != store.get<ESM::SoundGenerator>().end(); ++sound)
162             {
163                 if (type == sound->mType && !sound->mCreature.empty() && (Misc::StringUtils::ciEqual(creatureId, sound->mCreature)))
164                     sounds.push_back(&*sound);
165                 if (type == sound->mType && sound->mCreature.empty())
166                     fallbacksounds.push_back(&*sound);
167             }
168 
169             if (!sounds.empty())
170                 return sounds[Misc::Rng::rollDice(sounds.size())]->mSound;
171             if (!fallbacksounds.empty())
172                 return fallbacksounds[Misc::Rng::rollDice(fallbacksounds.size())]->mSound;
173         }
174         else
175         {
176             // The activator doesn't have a corresponding creature ID, but we can try to use the defaults
177             for (auto sound = store.get<ESM::SoundGenerator>().begin(); sound != store.get<ESM::SoundGenerator>().end(); ++sound)
178                 if (type == sound->mType && sound->mCreature.empty())
179                     fallbacksounds.push_back(&*sound);
180 
181             if (!fallbacksounds.empty())
182                 return fallbacksounds[Misc::Rng::rollDice(fallbacksounds.size())]->mSound;
183         }
184 
185         return std::string();
186     }
187 
getSndGenTypeFromName(const std::string & name)188     int Activator::getSndGenTypeFromName(const std::string &name)
189     {
190         if (name == "left")
191             return ESM::SoundGenerator::LeftFoot;
192         if (name == "right")
193             return ESM::SoundGenerator::RightFoot;
194         if (name == "swimleft")
195             return ESM::SoundGenerator::SwimLeft;
196         if (name == "swimright")
197             return ESM::SoundGenerator::SwimRight;
198         if (name == "moan")
199             return ESM::SoundGenerator::Moan;
200         if (name == "roar")
201             return ESM::SoundGenerator::Roar;
202         if (name == "scream")
203             return ESM::SoundGenerator::Scream;
204         if (name == "land")
205             return ESM::SoundGenerator::Land;
206 
207         throw std::runtime_error(std::string("Unexpected soundgen type: ")+name);
208     }
209 }
210