mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-01-31 15:32:45 +00:00
42e45723b7
Fixes issue when fetching MyGui values that were stored as RefId but fetched as String Removed some uncessary copies, fixed issues with lowercase and uneeded changes
228 lines
7.9 KiB
C++
228 lines
7.9 KiB
C++
#include "weaponanimation.hpp"
|
|
|
|
#include <osg/MatrixTransform>
|
|
|
|
#include <components/resource/resourcesystem.hpp>
|
|
#include <components/resource/scenemanager.hpp>
|
|
|
|
#include "../mwbase/environment.hpp"
|
|
#include "../mwbase/soundmanager.hpp"
|
|
#include "../mwbase/world.hpp"
|
|
|
|
#include "../mwworld/class.hpp"
|
|
#include "../mwworld/esmstore.hpp"
|
|
#include "../mwworld/inventorystore.hpp"
|
|
|
|
#include "../mwmechanics/combat.hpp"
|
|
#include "../mwmechanics/weapontype.hpp"
|
|
|
|
#include "animation.hpp"
|
|
#include "rotatecontroller.hpp"
|
|
|
|
namespace MWRender
|
|
{
|
|
|
|
float WeaponAnimationTime::getValue(osg::NodeVisitor*)
|
|
{
|
|
if (mWeaponGroup.empty())
|
|
return 0;
|
|
|
|
float current = mAnimation->getCurrentTime(mWeaponGroup);
|
|
if (current == -1)
|
|
return 0;
|
|
return current - mStartTime;
|
|
}
|
|
|
|
void WeaponAnimationTime::setGroup(const std::string& group, bool relativeTime)
|
|
{
|
|
mWeaponGroup = group;
|
|
mRelativeTime = relativeTime;
|
|
|
|
if (mRelativeTime)
|
|
mStartTime = mAnimation->getStartTime(mWeaponGroup);
|
|
else
|
|
mStartTime = 0;
|
|
}
|
|
|
|
void WeaponAnimationTime::updateStartTime()
|
|
{
|
|
setGroup(mWeaponGroup, mRelativeTime);
|
|
}
|
|
|
|
WeaponAnimation::WeaponAnimation()
|
|
: mPitchFactor(0)
|
|
{
|
|
}
|
|
|
|
WeaponAnimation::~WeaponAnimation() {}
|
|
|
|
void WeaponAnimation::attachArrow(const MWWorld::Ptr& actor)
|
|
{
|
|
const MWWorld::InventoryStore& inv = actor.getClass().getInventoryStore(actor);
|
|
MWWorld::ConstContainerStoreIterator weaponSlot = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
|
if (weaponSlot == inv.end())
|
|
return;
|
|
if (weaponSlot->getType() != ESM::Weapon::sRecordId)
|
|
return;
|
|
|
|
int type = weaponSlot->get<ESM::Weapon>()->mBase->mData.mType;
|
|
ESM::WeaponType::Class weapclass = MWMechanics::getWeaponType(type)->mWeaponClass;
|
|
if (weapclass == ESM::WeaponType::Thrown)
|
|
{
|
|
const auto& soundid = weaponSlot->getClass().getUpSoundId(*weaponSlot);
|
|
if (!soundid.empty())
|
|
{
|
|
MWBase::SoundManager* sndMgr = MWBase::Environment::get().getSoundManager();
|
|
sndMgr->playSound3D(actor, soundid, 1.0f, 1.0f);
|
|
}
|
|
showWeapon(true);
|
|
}
|
|
else if (weapclass == ESM::WeaponType::Ranged)
|
|
{
|
|
osg::Group* parent = getArrowBone();
|
|
if (!parent)
|
|
return;
|
|
|
|
MWWorld::ConstContainerStoreIterator ammo = inv.getSlot(MWWorld::InventoryStore::Slot_Ammunition);
|
|
if (ammo == inv.end())
|
|
return;
|
|
std::string model = ammo->getClass().getModel(*ammo);
|
|
|
|
osg::ref_ptr<osg::Node> arrow = getResourceSystem()->getSceneManager()->getInstance(model, parent);
|
|
|
|
mAmmunition = std::make_unique<PartHolder>(arrow);
|
|
}
|
|
}
|
|
|
|
void WeaponAnimation::detachArrow(MWWorld::Ptr actor)
|
|
{
|
|
mAmmunition.reset();
|
|
}
|
|
|
|
void WeaponAnimation::releaseArrow(MWWorld::Ptr actor, float attackStrength)
|
|
{
|
|
MWWorld::InventoryStore& inv = actor.getClass().getInventoryStore(actor);
|
|
MWWorld::ContainerStoreIterator weapon = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
|
if (weapon == inv.end())
|
|
return;
|
|
if (weapon->getType() != ESM::Weapon::sRecordId)
|
|
return;
|
|
|
|
// The orientation of the launched projectile. Always the same as the actor orientation, even if the ArrowBone's
|
|
// 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));
|
|
|
|
const MWWorld::Store<ESM::GameSetting>& gmst
|
|
= MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
|
|
|
MWMechanics::applyFatigueLoss(actor, *weapon, attackStrength);
|
|
|
|
if (MWMechanics::getWeaponType(weapon->get<ESM::Weapon>()->mBase->mData.mType)->mWeaponClass
|
|
== ESM::WeaponType::Thrown)
|
|
{
|
|
// Thrown weapons get detached now
|
|
osg::Node* weaponNode = getWeaponNode();
|
|
if (!weaponNode)
|
|
return;
|
|
osg::NodePathList nodepaths = weaponNode->getParentalNodePaths();
|
|
if (nodepaths.empty())
|
|
return;
|
|
osg::Vec3f launchPos = osg::computeLocalToWorld(nodepaths[0]).getTrans();
|
|
|
|
float fThrownWeaponMinSpeed = gmst.find("fThrownWeaponMinSpeed")->mValue.getFloat();
|
|
float fThrownWeaponMaxSpeed = gmst.find("fThrownWeaponMaxSpeed")->mValue.getFloat();
|
|
float speed = fThrownWeaponMinSpeed + (fThrownWeaponMaxSpeed - fThrownWeaponMinSpeed) * attackStrength;
|
|
|
|
MWWorld::Ptr weaponPtr = *weapon;
|
|
MWBase::Environment::get().getWorld()->launchProjectile(
|
|
actor, weaponPtr, launchPos, orient, weaponPtr, speed, attackStrength);
|
|
|
|
showWeapon(false);
|
|
|
|
inv.remove(*weapon, 1, actor);
|
|
}
|
|
else
|
|
{
|
|
// With bows and crossbows only the used arrow/bolt gets detached
|
|
MWWorld::ContainerStoreIterator ammo = inv.getSlot(MWWorld::InventoryStore::Slot_Ammunition);
|
|
if (ammo == inv.end())
|
|
return;
|
|
|
|
if (!mAmmunition)
|
|
return;
|
|
|
|
osg::ref_ptr<osg::Node> ammoNode = mAmmunition->getNode();
|
|
osg::NodePathList nodepaths = ammoNode->getParentalNodePaths();
|
|
if (nodepaths.empty())
|
|
return;
|
|
osg::Vec3f launchPos = osg::computeLocalToWorld(nodepaths[0]).getTrans();
|
|
|
|
float fProjectileMinSpeed = gmst.find("fProjectileMinSpeed")->mValue.getFloat();
|
|
float fProjectileMaxSpeed = gmst.find("fProjectileMaxSpeed")->mValue.getFloat();
|
|
float speed = fProjectileMinSpeed + (fProjectileMaxSpeed - fProjectileMinSpeed) * attackStrength;
|
|
|
|
MWWorld::Ptr weaponPtr = *weapon;
|
|
MWWorld::Ptr ammoPtr = *ammo;
|
|
MWBase::Environment::get().getWorld()->launchProjectile(
|
|
actor, ammoPtr, launchPos, orient, weaponPtr, speed, attackStrength);
|
|
|
|
inv.remove(ammoPtr, 1, actor);
|
|
mAmmunition.reset();
|
|
}
|
|
}
|
|
|
|
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)
|
|
{
|
|
for (int i = 0; i < 2; ++i)
|
|
{
|
|
mSpineControllers[i] = nullptr;
|
|
|
|
Animation::NodeMap::const_iterator found = nodes.find(i == 0 ? "bip01 spine1" : "bip01 spine2");
|
|
if (found != nodes.end())
|
|
{
|
|
osg::Node* node = found->second;
|
|
mSpineControllers[i] = new RotateController(objectRoot);
|
|
node->addUpdateCallback(mSpineControllers[i]);
|
|
map.emplace_back(node, mSpineControllers[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
void WeaponAnimation::deleteControllers()
|
|
{
|
|
for (int i = 0; i < 2; ++i)
|
|
mSpineControllers[i] = nullptr;
|
|
}
|
|
|
|
void WeaponAnimation::configureControllers(float characterPitchRadians)
|
|
{
|
|
if (mPitchFactor == 0.f || characterPitchRadians == 0.f)
|
|
{
|
|
setControllerEnabled(false);
|
|
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)
|
|
{
|
|
for (int i = 0; i < 2; ++i)
|
|
if (mSpineControllers[i])
|
|
mSpineControllers[i]->setRotate(rotate);
|
|
}
|
|
|
|
void WeaponAnimation::setControllerEnabled(bool enabled)
|
|
{
|
|
for (int i = 0; i < 2; ++i)
|
|
if (mSpineControllers[i])
|
|
mSpineControllers[i]->setEnabled(enabled);
|
|
}
|
|
|
|
}
|