1 #include "weaponanimation.hpp"
2
3 #include <osg/MatrixTransform>
4
5 #include <components/resource/resourcesystem.hpp>
6 #include <components/resource/scenemanager.hpp>
7
8 #include "../mwbase/world.hpp"
9 #include "../mwbase/environment.hpp"
10 #include "../mwbase/soundmanager.hpp"
11
12 #include "../mwworld/inventorystore.hpp"
13 #include "../mwworld/class.hpp"
14 #include "../mwworld/esmstore.hpp"
15
16 #include "../mwmechanics/creaturestats.hpp"
17 #include "../mwmechanics/combat.hpp"
18 #include "../mwmechanics/weapontype.hpp"
19
20 #include "animation.hpp"
21 #include "rotatecontroller.hpp"
22
23 namespace MWRender
24 {
25
getValue(osg::NodeVisitor *)26 float WeaponAnimationTime::getValue(osg::NodeVisitor*)
27 {
28 if (mWeaponGroup.empty())
29 return 0;
30
31 float current = mAnimation->getCurrentTime(mWeaponGroup);
32 if (current == -1)
33 return 0;
34 return current - mStartTime;
35 }
36
setGroup(const std::string & group,bool relativeTime)37 void WeaponAnimationTime::setGroup(const std::string &group, bool relativeTime)
38 {
39 mWeaponGroup = group;
40 mRelativeTime = relativeTime;
41
42 if (mRelativeTime)
43 mStartTime = mAnimation->getStartTime(mWeaponGroup);
44 else
45 mStartTime = 0;
46 }
47
updateStartTime()48 void WeaponAnimationTime::updateStartTime()
49 {
50 setGroup(mWeaponGroup, mRelativeTime);
51 }
52
WeaponAnimation()53 WeaponAnimation::WeaponAnimation()
54 : mPitchFactor(0)
55 {
56 }
57
~WeaponAnimation()58 WeaponAnimation::~WeaponAnimation()
59 {
60
61 }
62
attachArrow(MWWorld::Ptr actor)63 void WeaponAnimation::attachArrow(MWWorld::Ptr actor)
64 {
65 const MWWorld::InventoryStore& inv = actor.getClass().getInventoryStore(actor);
66 MWWorld::ConstContainerStoreIterator weaponSlot = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
67 if (weaponSlot == inv.end())
68 return;
69 if (weaponSlot->getTypeName() != typeid(ESM::Weapon).name())
70 return;
71
72 int type = weaponSlot->get<ESM::Weapon>()->mBase->mData.mType;
73 ESM::WeaponType::Class weapclass = MWMechanics::getWeaponType(type)->mWeaponClass;
74 if (weapclass == ESM::WeaponType::Thrown)
75 {
76 std::string soundid = weaponSlot->getClass().getUpSoundId(*weaponSlot);
77 if(!soundid.empty())
78 {
79 MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
80 sndMgr->playSound3D(actor, soundid, 1.0f, 1.0f);
81 }
82 showWeapon(true);
83 }
84 else if (weapclass == ESM::WeaponType::Ranged)
85 {
86 osg::Group* parent = getArrowBone();
87 if (!parent)
88 return;
89
90 MWWorld::ConstContainerStoreIterator ammo = inv.getSlot(MWWorld::InventoryStore::Slot_Ammunition);
91 if (ammo == inv.end())
92 return;
93 std::string model = ammo->getClass().getModel(*ammo);
94
95 osg::ref_ptr<osg::Node> arrow = getResourceSystem()->getSceneManager()->getInstance(model, parent);
96
97 mAmmunition = PartHolderPtr(new PartHolder(arrow));
98 }
99 }
100
detachArrow(MWWorld::Ptr actor)101 void WeaponAnimation::detachArrow(MWWorld::Ptr actor)
102 {
103 mAmmunition.reset();
104 }
105
releaseArrow(MWWorld::Ptr actor,float attackStrength)106 void WeaponAnimation::releaseArrow(MWWorld::Ptr actor, float attackStrength)
107 {
108 MWWorld::InventoryStore& inv = actor.getClass().getInventoryStore(actor);
109 MWWorld::ContainerStoreIterator weapon = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
110 if (weapon == inv.end())
111 return;
112 if (weapon->getTypeName() != typeid(ESM::Weapon).name())
113 return;
114
115 // The orientation of the launched projectile. Always the same as the actor orientation, even if the ArrowBone's orientation dictates otherwise.
116 osg::Quat orient = osg::Quat(actor.getRefData().getPosition().rot[0], osg::Vec3f(-1,0,0))
117 * osg::Quat(actor.getRefData().getPosition().rot[2], osg::Vec3f(0,0,-1));
118
119 const MWWorld::Store<ESM::GameSetting> &gmst =
120 MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
121
122 MWMechanics::applyFatigueLoss(actor, *weapon, attackStrength);
123
124 if (MWMechanics::getWeaponType(weapon->get<ESM::Weapon>()->mBase->mData.mType)->mWeaponClass == ESM::WeaponType::Thrown)
125 {
126 // Thrown weapons get detached now
127 osg::Node* weaponNode = getWeaponNode();
128 if (!weaponNode)
129 return;
130 osg::NodePathList nodepaths = weaponNode->getParentalNodePaths();
131 if (nodepaths.empty())
132 return;
133 osg::Vec3f launchPos = osg::computeLocalToWorld(nodepaths[0]).getTrans();
134
135 float fThrownWeaponMinSpeed = gmst.find("fThrownWeaponMinSpeed")->mValue.getFloat();
136 float fThrownWeaponMaxSpeed = gmst.find("fThrownWeaponMaxSpeed")->mValue.getFloat();
137 float speed = fThrownWeaponMinSpeed + (fThrownWeaponMaxSpeed - fThrownWeaponMinSpeed) * attackStrength;
138
139 MWWorld::Ptr weaponPtr = *weapon;
140 MWBase::Environment::get().getWorld()->launchProjectile(actor, weaponPtr, launchPos, orient, weaponPtr, speed, attackStrength);
141
142 showWeapon(false);
143
144 inv.remove(*weapon, 1, actor);
145 }
146 else
147 {
148 // With bows and crossbows only the used arrow/bolt gets detached
149 MWWorld::ContainerStoreIterator ammo = inv.getSlot(MWWorld::InventoryStore::Slot_Ammunition);
150 if (ammo == inv.end())
151 return;
152
153 if (!mAmmunition)
154 return;
155
156 osg::ref_ptr<osg::Node> ammoNode = mAmmunition->getNode();
157 osg::NodePathList nodepaths = ammoNode->getParentalNodePaths();
158 if (nodepaths.empty())
159 return;
160 osg::Vec3f launchPos = osg::computeLocalToWorld(nodepaths[0]).getTrans();
161
162 float fProjectileMinSpeed = gmst.find("fProjectileMinSpeed")->mValue.getFloat();
163 float fProjectileMaxSpeed = gmst.find("fProjectileMaxSpeed")->mValue.getFloat();
164 float speed = fProjectileMinSpeed + (fProjectileMaxSpeed - fProjectileMinSpeed) * attackStrength;
165
166 MWWorld::Ptr weaponPtr = *weapon;
167 MWWorld::Ptr ammoPtr = *ammo;
168 MWBase::Environment::get().getWorld()->launchProjectile(actor, ammoPtr, launchPos, orient, weaponPtr, speed, attackStrength);
169
170 inv.remove(ammoPtr, 1, actor);
171 mAmmunition.reset();
172 }
173 }
174
addControllers(const std::map<std::string,osg::ref_ptr<osg::MatrixTransform>> & nodes,std::vector<std::pair<osg::ref_ptr<osg::Node>,osg::ref_ptr<osg::NodeCallback>>> & map,osg::Node * objectRoot)175 void WeaponAnimation::addControllers(const std::map<std::string, osg::ref_ptr<osg::MatrixTransform> >& nodes,
176 std::vector<std::pair<osg::ref_ptr<osg::Node>, osg::ref_ptr<osg::NodeCallback>>> &map, osg::Node* objectRoot)
177 {
178 for (int i=0; i<2; ++i)
179 {
180 mSpineControllers[i] = nullptr;
181
182 std::map<std::string, osg::ref_ptr<osg::MatrixTransform> >::const_iterator found = nodes.find(i == 0 ? "bip01 spine1" : "bip01 spine2");
183 if (found != nodes.end())
184 {
185 osg::Node* node = found->second;
186 mSpineControllers[i] = new RotateController(objectRoot);
187 node->addUpdateCallback(mSpineControllers[i]);
188 map.emplace_back(node, mSpineControllers[i]);
189 }
190 }
191 }
192
deleteControllers()193 void WeaponAnimation::deleteControllers()
194 {
195 for (int i=0; i<2; ++i)
196 mSpineControllers[i] = nullptr;
197 }
198
configureControllers(float characterPitchRadians)199 void WeaponAnimation::configureControllers(float characterPitchRadians)
200 {
201 if (mPitchFactor == 0.f || characterPitchRadians == 0.f)
202 {
203 setControllerEnabled(false);
204 return;
205 }
206
207 float pitch = characterPitchRadians * mPitchFactor;
208 osg::Quat rotate (pitch/2, osg::Vec3f(-1,0,0));
209 setControllerRotate(rotate);
210 setControllerEnabled(true);
211 }
212
setControllerRotate(const osg::Quat & rotate)213 void WeaponAnimation::setControllerRotate(const osg::Quat& rotate)
214 {
215 for (int i=0; i<2; ++i)
216 if (mSpineControllers[i])
217 mSpineControllers[i]->setRotate(rotate);
218 }
219
setControllerEnabled(bool enabled)220 void WeaponAnimation::setControllerEnabled(bool enabled)
221 {
222 for (int i=0; i<2; ++i)
223 if (mSpineControllers[i])
224 mSpineControllers[i]->setEnabled(enabled);
225 }
226
227 }
228