1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-01-29 09:32:45 +00:00
OpenMW/apps/openmw/mwrender/weaponanimation.cpp

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

228 lines
7.9 KiB
C++
Raw Normal View History

2014-03-12 11:30:44 +01:00
#include "weaponanimation.hpp"
2015-05-31 18:53:16 +02:00
#include <osg/MatrixTransform>
2015-05-31 01:07:43 +02:00
#include <components/resource/resourcesystem.hpp>
#include <components/resource/scenemanager.hpp>
2014-03-12 11:30:44 +01:00
#include "../mwbase/environment.hpp"
#include "../mwbase/soundmanager.hpp"
2014-03-12 11:30:44 +01:00
#include "../mwbase/world.hpp"
#include "../mwworld/class.hpp"
#include "../mwworld/esmstore.hpp"
#include "../mwworld/inventorystore.hpp"
2015-01-31 22:28:23 +01:00
#include "../mwmechanics/combat.hpp"
#include "../mwmechanics/weapontype.hpp"
2014-03-12 11:30:44 +01:00
#include "animation.hpp"
2015-05-31 18:53:16 +02:00
#include "rotatecontroller.hpp"
2014-03-12 11:30:44 +01:00
namespace MWRender
{
2015-05-31 01:07:43 +02:00
float WeaponAnimationTime::getValue(osg::NodeVisitor*)
2014-03-12 11:30:44 +01:00
{
if (mWeaponGroup.empty())
return 0;
2014-03-12 11:30:44 +01:00
2015-05-31 01:07:43 +02:00
float current = mAnimation->getCurrentTime(mWeaponGroup);
if (current == -1)
2014-03-12 11:30:44 +01:00
return 0;
2015-05-31 01:07:43 +02:00
return current - mStartTime;
}
2015-05-31 18:53:16 +02:00
void WeaponAnimationTime::setGroup(const std::string& group, bool relativeTime)
2022-09-22 21:26:05 +03:00
{
2015-05-31 18:53:16 +02:00
mWeaponGroup = group;
mRelativeTime = relativeTime;
2015-05-31 18:53:16 +02:00
if (mRelativeTime)
mStartTime = mAnimation->getStartTime(mWeaponGroup);
2022-09-22 21:26:05 +03:00
else
mStartTime = 0;
2015-05-31 18:53:16 +02:00
}
2021-08-15 19:50:28 +02:00
void WeaponAnimationTime::updateStartTime()
{
setGroup(mWeaponGroup, mRelativeTime);
}
2022-08-21 18:53:38 +02:00
WeaponAnimation::WeaponAnimation()
: mPitchFactor(0)
2022-09-22 21:26:05 +03:00
{
2014-03-12 11:30:44 +01:00
}
WeaponAnimation::~WeaponAnimation() {}
void WeaponAnimation::attachArrow(const MWWorld::Ptr& actor)
2014-03-12 11:30:44 +01:00
{
const MWWorld::InventoryStore& inv = actor.getClass().getInventoryStore(actor);
2015-05-31 01:07:43 +02:00
MWWorld::ConstContainerStoreIterator weaponSlot = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
if (weaponSlot == inv.end())
return;
if (weaponSlot->getType() != ESM::Weapon::sRecordId)
2015-05-31 01:07:43 +02:00
return;
2014-03-12 11:30:44 +01:00
2018-08-29 18:38:12 +03:00
int type = weaponSlot->get<ESM::Weapon>()->mBase->mData.mType;
ESM::WeaponType::Class weapclass = MWMechanics::getWeaponType(type)->mWeaponClass;
2018-08-29 18:38:12 +03:00
if (weapclass == ESM::WeaponType::Thrown)
2022-09-22 21:26:05 +03:00
{
const auto& soundid = weaponSlot->getClass().getUpSoundId(*weaponSlot);
if (!soundid.empty())
2022-09-22 21:26:05 +03:00
{
2018-08-29 18:38:12 +03:00
MWBase::SoundManager* sndMgr = MWBase::Environment::get().getSoundManager();
sndMgr->playSound3D(actor, soundid, 1.0f, 1.0f);
2022-09-22 21:26:05 +03:00
}
showWeapon(true);
2022-09-22 21:26:05 +03:00
}
else if (weapclass == ESM::WeaponType::Ranged)
2022-09-22 21:26:05 +03:00
{
osg::Group* parent = getArrowBone();
2015-05-31 01:07:43 +02:00
if (!parent)
2022-09-22 21:26:05 +03:00
return;
2014-03-12 11:30:44 +01:00
MWWorld::ConstContainerStoreIterator ammo = inv.getSlot(MWWorld::InventoryStore::Slot_Ammunition);
if (ammo == inv.end())
2022-09-22 21:26:05 +03:00
return;
2024-08-18 20:23:11 +02:00
VFS::Path::Normalized model(ammo->getClass().getCorrectedModel(*ammo));
2014-03-12 11:30:44 +01:00
osg::ref_ptr<osg::Node> arrow = getResourceSystem()->getSceneManager()->getInstance(model, parent);
mAmmunition = std::make_unique<PartHolder>(arrow);
2022-09-22 21:26:05 +03:00
}
2014-03-12 11:30:44 +01:00
}
2022-09-22 21:26:05 +03:00
void WeaponAnimation::detachArrow(MWWorld::Ptr actor)
2014-03-12 11:30:44 +01:00
{
mAmmunition.reset();
2022-09-22 21:26:05 +03:00
}
2014-03-12 11:30:44 +01:00
2015-05-31 01:07:43 +02:00
void WeaponAnimation::releaseArrow(MWWorld::Ptr actor, float attackStrength)
2022-09-22 21:26:05 +03:00
{
2014-03-12 11:30:44 +01:00
MWWorld::InventoryStore& inv = actor.getClass().getInventoryStore(actor);
2015-05-31 01:07:43 +02:00
MWWorld::ContainerStoreIterator weapon = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
if (weapon == inv.end())
2015-01-04 01:33:36 +01:00
return;
2015-05-31 01:07:43 +02:00
if (weapon->getType() != ESM::Weapon::sRecordId)
return;
2014-03-12 11:30:44 +01:00
// The orientation of the launched projectile. Always the same as the actor orientation, even if the ArrowBone's
2014-03-12 11:30:44 +01:00
// orientation dictates otherwise.
osg::Quat orient = osg::Quat(actor.getRefData().getPosition().rot[0], osg::Vec3f(-1, 0, 0))
* osg::Quat(actor.getRefData().getPosition().rot[2], osg::Vec3f(0, 0, -1));
2014-03-12 11:30:44 +01:00
const MWWorld::Store<ESM::GameSetting>& gmst
2023-04-20 21:07:53 +02:00
= MWBase::Environment::get().getESMStore()->get<ESM::GameSetting>();
2014-03-12 11:30:44 +01:00
MWMechanics::applyFatigueLoss(actor, *weapon, attackStrength);
2022-09-22 21:26:05 +03:00
if (MWMechanics::getWeaponType(weapon->get<ESM::Weapon>()->mBase->mData.mType)->mWeaponClass
== ESM::WeaponType::Thrown)
2022-09-22 21:26:05 +03:00
{
2014-03-12 11:30:44 +01:00
// Thrown weapons get detached now
2015-05-31 01:07:43 +02:00
osg::Node* weaponNode = getWeaponNode();
if (!weaponNode)
2022-09-22 21:26:05 +03:00
return;
osg::NodePathList nodepaths = weaponNode->getParentalNodePaths();
if (nodepaths.empty())
2022-09-22 21:26:05 +03:00
return;
osg::Vec3f launchPos = osg::computeLocalToWorld(nodepaths[0]).getTrans();
2022-09-22 21:26:05 +03:00
2018-08-29 18:38:12 +03:00
float fThrownWeaponMinSpeed = gmst.find("fThrownWeaponMinSpeed")->mValue.getFloat();
float fThrownWeaponMaxSpeed = gmst.find("fThrownWeaponMaxSpeed")->mValue.getFloat();
float speed = fThrownWeaponMinSpeed + (fThrownWeaponMaxSpeed - fThrownWeaponMinSpeed) * attackStrength;
2022-09-22 21:26:05 +03:00
MWWorld::Ptr weaponPtr = *weapon;
2014-03-12 11:30:44 +01:00
MWBase::Environment::get().getWorld()->launchProjectile(
actor, weaponPtr, launchPos, orient, weaponPtr, speed, attackStrength);
2022-09-22 21:26:05 +03:00
2014-03-12 11:30:44 +01:00
showWeapon(false);
2022-09-22 21:26:05 +03:00
inv.remove(*weapon, 1);
2022-09-22 21:26:05 +03:00
}
else
{
2014-03-12 11:30:44 +01:00
// With bows and crossbows only the used arrow/bolt gets detached
MWWorld::ContainerStoreIterator ammo = inv.getSlot(MWWorld::InventoryStore::Slot_Ammunition);
2014-03-12 11:30:44 +01:00
if (ammo == inv.end())
2022-09-22 21:26:05 +03:00
return;
if (!mAmmunition)
2022-09-22 21:26:05 +03:00
return;
2015-05-31 01:07:43 +02:00
osg::ref_ptr<osg::Node> ammoNode = mAmmunition->getNode();
osg::NodePathList nodepaths = ammoNode->getParentalNodePaths();
if (nodepaths.empty())
2022-09-22 21:26:05 +03:00
return;
osg::Vec3f launchPos = osg::computeLocalToWorld(nodepaths[0]).getTrans();
2022-09-22 21:26:05 +03:00
2018-08-29 18:38:12 +03:00
float fProjectileMinSpeed = gmst.find("fProjectileMinSpeed")->mValue.getFloat();
float fProjectileMaxSpeed = gmst.find("fProjectileMaxSpeed")->mValue.getFloat();
float speed = fProjectileMinSpeed + (fProjectileMaxSpeed - fProjectileMinSpeed) * attackStrength;
2022-09-22 21:26:05 +03:00
MWWorld::Ptr weaponPtr = *weapon;
MWWorld::Ptr ammoPtr = *ammo;
2014-03-12 11:30:44 +01:00
MWBase::Environment::get().getWorld()->launchProjectile(
actor, ammoPtr, launchPos, orient, weaponPtr, speed, attackStrength);
2022-09-22 21:26:05 +03:00
inv.remove(ammoPtr, 1);
2015-05-31 01:07:43 +02:00
mAmmunition.reset();
2022-09-22 21:26:05 +03:00
}
2014-03-12 11:30:44 +01:00
}
void WeaponAnimation::addControllers(const Animation::NodeMap& nodes,
std::vector<std::pair<osg::ref_ptr<osg::Node>, osg::ref_ptr<osg::Callback>>>& map, osg::Node* objectRoot)
2015-05-31 18:53:16 +02:00
{
for (int i = 0; i < 2; ++i)
2015-05-31 18:53:16 +02:00
{
2018-10-09 10:21:12 +04:00
mSpineControllers[i] = nullptr;
2022-09-22 21:26:05 +03:00
Animation::NodeMap::const_iterator found = nodes.find(i == 0 ? "bip01 spine1" : "bip01 spine2");
2015-05-31 18:53:16 +02:00
if (found != nodes.end())
2022-09-22 21:26:05 +03:00
{
2015-05-31 18:53:16 +02:00
osg::Node* node = found->second;
mSpineControllers[i] = new RotateController(objectRoot);
node->addUpdateCallback(mSpineControllers[i]);
map.emplace_back(node, mSpineControllers[i]);
2022-09-22 21:26:05 +03:00
}
2015-05-31 18:53:16 +02:00
}
}
2015-05-31 18:53:16 +02:00
void WeaponAnimation::deleteControllers()
{
for (int i = 0; i < 2; ++i)
mSpineControllers[i] = nullptr;
2015-05-31 18:53:16 +02:00
}
void WeaponAnimation::configureControllers(float characterPitchRadians)
2022-09-22 21:26:05 +03:00
{
2015-05-31 18:53:16 +02:00
if (mPitchFactor == 0.f || characterPitchRadians == 0.f)
2022-09-22 21:26:05 +03:00
{
setControllerEnabled(false);
2022-09-22 21:26:05 +03:00
return;
}
float pitch = characterPitchRadians * mPitchFactor;
osg::Quat rotate(pitch / 2, osg::Vec3f(-1, 0, 0));
setControllerRotate(rotate);
setControllerEnabled(true);
}
void WeaponAnimation::setControllerRotate(const osg::Quat& rotate)
2022-09-22 21:26:05 +03:00
{
2015-05-31 18:53:16 +02:00
for (int i = 0; i < 2; ++i)
if (mSpineControllers[i])
mSpineControllers[i]->setRotate(rotate);
2022-09-22 21:26:05 +03:00
}
void WeaponAnimation::setControllerEnabled(bool enabled)
{
for (int i = 0; i < 2; ++i)
if (mSpineControllers[i])
mSpineControllers[i]->setEnabled(enabled);
2014-03-12 11:30:44 +01:00
}
}