1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-10-10 17:56:32 +00:00

Show full player body when knocked out or dead

This commit is contained in:
Mads Buvik Sandvei 2020-03-28 16:30:56 +01:00
parent 68c75f66eb
commit d658065fe7
10 changed files with 97 additions and 50 deletions

View file

@ -39,6 +39,7 @@
#include "../mwworld/inventorystore.hpp" #include "../mwworld/inventorystore.hpp"
#include "../mwworld/esmstore.hpp" #include "../mwworld/esmstore.hpp"
#include "../mwworld/player.hpp" #include "../mwworld/player.hpp"
#include "../mwrender/npcanimation.hpp"
#include "aicombataction.hpp" #include "aicombataction.hpp"
#include "movement.hpp" #include "movement.hpp"
@ -2377,6 +2378,18 @@ void CharacterController::update(float duration, bool animationOnly)
mSkipAnim = false; mSkipAnim = false;
mAnimation->enableHeadAnimation(cls.isActor() && !cls.getCreatureStats(mPtr).isDead()); mAnimation->enableHeadAnimation(cls.isActor() && !cls.getCreatureStats(mPtr).isDead());
#ifdef USE_OPENXR
if (isPlayer)
{
auto disabled = MWBase::Environment::get().getWorld()->getPlayer().isDisabled();
auto animation = static_cast<MWRender::NpcAnimation*>(mAnimation);
if (disabled)
animation->setViewMode(MWRender::NpcAnimation::VM_VRNormal);
else
animation->setViewMode(MWRender::NpcAnimation::VM_VRFirstPerson);
}
#endif
} }
void CharacterController::persistAnimationState() void CharacterController::persistAnimationState()

View file

@ -286,6 +286,7 @@ namespace MWPhysics
return position; return position;
const bool isPlayer = (ptr == MWMechanics::getPlayer()); const bool isPlayer = (ptr == MWMechanics::getPlayer());
auto* world = MWBase::Environment::get().getWorld();
// In VR, player should move according to current direction of // In VR, player should move according to current direction of
// a selected limb, rather than current orientation of camera. // a selected limb, rather than current orientation of camera.
@ -320,7 +321,7 @@ namespace MWPhysics
// While this is strictly speaking wrong, it's needed for MW compatibility. // While this is strictly speaking wrong, it's needed for MW compatibility.
position.z() += halfExtents.z(); position.z() += halfExtents.z();
static const float fSwimHeightScale = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>() static const float fSwimHeightScale = world->getStore().get<ESM::GameSetting>()
.find("fSwimHeightScale")->mValue.getFloat(); .find("fSwimHeightScale")->mValue.getFloat();
float swimlevel = waterlevel + halfExtents.z() - (physicActor->getRenderingHalfExtents().z() * 2 * fSwimHeightScale); float swimlevel = waterlevel + halfExtents.z() - (physicActor->getRenderingHalfExtents().z() * 2 * fSwimHeightScale);
@ -355,13 +356,13 @@ namespace MWPhysics
if (isPlayer) if (isPlayer)
{ {
ptr.getClass().skillUsageSucceeded(ptr, ESM::Skill::Acrobatics, 0); ptr.getClass().skillUsageSucceeded(ptr, ESM::Skill::Acrobatics, 0);
MWBase::Environment::get().getWorld()->getPlayer().setJumping(true); world->getPlayer().setJumping(true);
} }
// Decrease fatigue // Decrease fatigue
if (!isPlayer || !MWBase::Environment::get().getWorld()->getGodModeState()) if (!isPlayer || !world->getGodModeState())
{ {
const MWWorld::Store<ESM::GameSetting> &gmst = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>(); const MWWorld::Store<ESM::GameSetting> &gmst = world->getStore().get<ESM::GameSetting>();
const float fFatigueJumpBase = gmst.find("fFatigueJumpBase")->mValue.getFloat(); const float fFatigueJumpBase = gmst.find("fFatigueJumpBase")->mValue.getFloat();
const float fFatigueJumpMult = gmst.find("fFatigueJumpMult")->mValue.getFloat(); const float fFatigueJumpMult = gmst.find("fFatigueJumpMult")->mValue.getFloat();
const float normalizedEncumbrance = std::min(1.f, ptr.getClass().getNormalizedEncumbrance(ptr)); const float normalizedEncumbrance = std::min(1.f, ptr.getClass().getNormalizedEncumbrance(ptr));
@ -374,11 +375,11 @@ namespace MWPhysics
} }
// Now that we have the effective movement vector, apply wind forces to it // Now that we have the effective movement vector, apply wind forces to it
if (MWBase::Environment::get().getWorld()->isInStorm()) if (world->isInStorm())
{ {
osg::Vec3f stormDirection = MWBase::Environment::get().getWorld()->getStormDirection(); osg::Vec3f stormDirection = world->getStormDirection();
float angleDegrees = osg::RadiansToDegrees(std::acos(stormDirection * velocity / (stormDirection.length() * velocity.length()))); float angleDegrees = osg::RadiansToDegrees(std::acos(stormDirection * velocity / (stormDirection.length() * velocity.length())));
static const float fStromWalkMult = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>() static const float fStromWalkMult = world->getStore().get<ESM::GameSetting>()
.find("fStromWalkMult")->mValue.getFloat(); .find("fStromWalkMult")->mValue.getFloat();
velocity *= 1.f-(fStromWalkMult * (angleDegrees/180.f)); velocity *= 1.f-(fStromWalkMult * (angleDegrees/180.f));
} }
@ -388,8 +389,9 @@ namespace MWPhysics
osg::Vec3f newPosition = position; osg::Vec3f newPosition = position;
#ifdef USE_OPENXR #ifdef USE_OPENXR
if (isPlayer) if (isPlayer && !world->getPlayer().isDisabled())
{ {
auto* inputManager = MWVR::Environment::get().getInputManager(); auto* inputManager = MWVR::Environment::get().getInputManager();
osg::Vec3 trackingOffset = inputManager->mHeadOffset; osg::Vec3 trackingOffset = inputManager->mHeadOffset;

View file

@ -417,11 +417,8 @@ namespace MWRender
void Camera::processViewChange() void Camera::processViewChange()
{ {
#ifdef USE_OPENXR #ifdef USE_OPENXR
mAnimation->setViewMode(NpcAnimation::VM_VRHeadless); //mAnimation->setViewMode(NpcAnimation::VM_VRFirstPerson);
// For comfort, in VR mode the camera should only track nodes that don't animate.
// As-is, only the first person mode adds any unanimated nodes, but we want the third-person mode body.
// So we look up the root node of the player to track that.
SceneUtil::FindByNameVisitor findRootVisitor("Player Root", osg::NodeVisitor::TRAVERSE_PARENTS); SceneUtil::FindByNameVisitor findRootVisitor("Player Root", osg::NodeVisitor::TRAVERSE_PARENTS);
mAnimation->getObjectRoot()->accept(findRootVisitor); mAnimation->getObjectRoot()->accept(findRootVisitor);
mTrackingNode = findRootVisitor.mFoundNode; mTrackingNode = findRootVisitor.mFoundNode;

View file

@ -949,7 +949,7 @@ void NpcAnimation::addControllers()
mActiveControllers.emplace(node, mFirstPersonNeckController); mActiveControllers.emplace(node, mFirstPersonNeckController);
} }
} }
else if (mViewMode == VM_Normal || mViewMode == VM_VRHeadless) else if (mViewMode != VM_HeadOnly)
{ {
WeaponAnimation::addControllers(mNodeMap, mActiveControllers, mObjectRoot.get()); WeaponAnimation::addControllers(mNodeMap, mActiveControllers, mObjectRoot.get());
} }

View file

@ -36,7 +36,8 @@ public:
VM_Normal, VM_Normal,
VM_FirstPerson, VM_FirstPerson,
VM_HeadOnly, VM_HeadOnly,
VM_VRHeadless, VM_VRNormal,
VM_VRFirstPerson,
}; };
protected: protected:

View file

@ -943,7 +943,7 @@ private:
auto player = mPlayer->getPlayer(); auto player = mPlayer->getPlayer();
if (!mRealisticCombat || mRealisticCombat->ptr != player) if (!mRealisticCombat || mRealisticCombat->ptr != player)
mRealisticCombat.reset(new RealisticCombat::StateMachine(player)); mRealisticCombat.reset(new RealisticCombat::StateMachine(player));
bool enabled = !guiMode && mPlayer->getDrawState() == MWMechanics::DrawState_Weapon; bool enabled = !guiMode && mPlayer->getDrawState() == MWMechanics::DrawState_Weapon && !mPlayer->isDisabled();
mRealisticCombat->update(dt, enabled); mRealisticCombat->update(dt, enabled);
} }
@ -1126,13 +1126,6 @@ private:
osg::Vec3 vrMovement = currentHeadPose.position - mPreviousHeadPose.position; osg::Vec3 vrMovement = currentHeadPose.position - mPreviousHeadPose.position;
mPreviousHeadPose = currentHeadPose; mPreviousHeadPose = currentHeadPose;
float yaw = 0.f;
float pitch = 0.f;
float roll = 0.f;
getEulerAngles(currentHeadPose.orientation, yaw, pitch, roll);
yaw += mYaw;
if (mRecenter) if (mRecenter)
{ {
mHeadOffset = osg::Vec3(0, 0, 0); mHeadOffset = osg::Vec3(0, 0, 0);
@ -1145,10 +1138,25 @@ private:
osg::Quat gameworldYaw = osg::Quat(mYaw, osg::Vec3(0, 0, -1)); osg::Quat gameworldYaw = osg::Quat(mYaw, osg::Vec3(0, 0, -1));
mHeadOffset += gameworldYaw * vrMovement; mHeadOffset += gameworldYaw * vrMovement;
float yaw = 0.f;
float pitch = 0.f;
float roll = 0.f;
getEulerAngles(currentHeadPose.orientation, yaw, pitch, roll);
yaw += mYaw;
mVrAngles[0] = pitch; mVrAngles[0] = pitch;
mVrAngles[1] = roll; mVrAngles[1] = roll;
mVrAngles[2] = yaw; mVrAngles[2] = yaw;
world->rotateObject(player, mVrAngles[0], mVrAngles[1], mVrAngles[2], MWBase::RotationFlag_none);
if (!mPlayer->isDisabled())
{
world->rotateObject(player, mVrAngles[0], mVrAngles[1], mVrAngles[2], MWBase::RotationFlag_none);
}
else {
// Update the camera directly to avoid rotating the disabled player
world->getRenderingManager().getCamera()->rotateCamera(-pitch, -roll, -yaw, false);
}
} }
} }

View file

@ -179,8 +179,6 @@ void ForearmController::operator()(osg::Node* node, osg::NodeVisitor* nv)
// Finally, set transform // Finally, set transform
transform->setMatrix(worldReference * osg::Matrix::inverse(worldToLimb) * transform->getMatrix()); transform->setMatrix(worldReference * osg::Matrix::inverse(worldToLimb) * transform->getMatrix());
Log(Debug::Verbose) << "Updating hand: " << node->getName();
// Omit nested callbacks to override animations of this node // Omit nested callbacks to override animations of this node
osg::ref_ptr<osg::Callback> ncb = getNestedCallback(); osg::ref_ptr<osg::Callback> ncb = getNestedCallback();
setNestedCallback(nullptr); setNestedCallback(nullptr);
@ -431,7 +429,7 @@ VRAnimation::VRAnimation(
const MWWorld::Ptr& ptr, osg::ref_ptr<osg::Group> parentNode, Resource::ResourceSystem* resourceSystem, const MWWorld::Ptr& ptr, osg::ref_ptr<osg::Group> parentNode, Resource::ResourceSystem* resourceSystem,
bool disableSounds, std::shared_ptr<OpenXRSession> xrSession) bool disableSounds, std::shared_ptr<OpenXRSession> xrSession)
// Note that i let it construct as 3rd person and then later update it to VM_VRHeadless // Note that i let it construct as 3rd person and then later update it to VM_VRHeadless
// when OpenMW sets the view mode of the camera object. // when the character controller updates
: MWRender::NpcAnimation(ptr, parentNode, resourceSystem, disableSounds, VM_Normal, 55.f) : MWRender::NpcAnimation(ptr, parentNode, resourceSystem, disableSounds, VM_Normal, 55.f)
, mSession(xrSession) , mSession(xrSession)
, mIndexFingerControllers{nullptr, nullptr} , mIndexFingerControllers{nullptr, nullptr}
@ -474,9 +472,12 @@ VRAnimation::~VRAnimation() {};
void VRAnimation::setViewMode(NpcAnimation::ViewMode viewMode) void VRAnimation::setViewMode(NpcAnimation::ViewMode viewMode)
{ {
if (viewMode != VM_VRHeadless) if (viewMode != VM_VRFirstPerson && viewMode != VM_VRNormal)
Log(Debug::Warning) << "View mode of VRAnimation may only be VM_VRHeadless"; {
NpcAnimation::setViewMode(VM_VRHeadless); Log(Debug::Warning) << "Attempted to set view mode of VRAnimation to non-vr mode. Defaulted to VM_VRFirstPerson.";
viewMode = VM_VRFirstPerson;
}
NpcAnimation::setViewMode(viewMode);
return; return;
} }
@ -484,25 +485,36 @@ void VRAnimation::updateParts()
{ {
NpcAnimation::updateParts(); NpcAnimation::updateParts();
// Hide head and hair to avoid getting them in the player's face if (mViewMode == VM_VRFirstPerson)
// TODO: Hair might be acceptable ? {
removeIndividualPart(ESM::PartReferenceType::PRT_Hair); // Hide everything other than the hands and feet.
removeIndividualPart(ESM::PartReferenceType::PRT_Head); removeIndividualPart(ESM::PartReferenceType::PRT_Hair);
removeIndividualPart(ESM::PartReferenceType::PRT_LForearm); removeIndividualPart(ESM::PartReferenceType::PRT_Head);
removeIndividualPart(ESM::PartReferenceType::PRT_LUpperarm); removeIndividualPart(ESM::PartReferenceType::PRT_LForearm);
removeIndividualPart(ESM::PartReferenceType::PRT_LWrist); removeIndividualPart(ESM::PartReferenceType::PRT_LUpperarm);
removeIndividualPart(ESM::PartReferenceType::PRT_RForearm); removeIndividualPart(ESM::PartReferenceType::PRT_LWrist);
removeIndividualPart(ESM::PartReferenceType::PRT_RUpperarm); removeIndividualPart(ESM::PartReferenceType::PRT_RForearm);
removeIndividualPart(ESM::PartReferenceType::PRT_RWrist); removeIndividualPart(ESM::PartReferenceType::PRT_RUpperarm);
removeIndividualPart(ESM::PartReferenceType::PRT_Cuirass); removeIndividualPart(ESM::PartReferenceType::PRT_RWrist);
removeIndividualPart(ESM::PartReferenceType::PRT_Groin); removeIndividualPart(ESM::PartReferenceType::PRT_Cuirass);
removeIndividualPart(ESM::PartReferenceType::PRT_Neck); removeIndividualPart(ESM::PartReferenceType::PRT_Groin);
removeIndividualPart(ESM::PartReferenceType::PRT_Skirt); removeIndividualPart(ESM::PartReferenceType::PRT_Neck);
removeIndividualPart(ESM::PartReferenceType::PRT_Tail); removeIndividualPart(ESM::PartReferenceType::PRT_Skirt);
removeIndividualPart(ESM::PartReferenceType::PRT_LLeg); removeIndividualPart(ESM::PartReferenceType::PRT_Tail);
removeIndividualPart(ESM::PartReferenceType::PRT_RLeg); removeIndividualPart(ESM::PartReferenceType::PRT_LLeg);
removeIndividualPart(ESM::PartReferenceType::PRT_LAnkle); removeIndividualPart(ESM::PartReferenceType::PRT_RLeg);
removeIndividualPart(ESM::PartReferenceType::PRT_RAnkle); removeIndividualPart(ESM::PartReferenceType::PRT_LAnkle);
removeIndividualPart(ESM::PartReferenceType::PRT_RAnkle);
removeIndividualPart(ESM::PartReferenceType::PRT_LKnee);
removeIndividualPart(ESM::PartReferenceType::PRT_RKnee);
}
else
{
removeIndividualPart(ESM::PartReferenceType::PRT_LForearm);
removeIndividualPart(ESM::PartReferenceType::PRT_LWrist);
removeIndividualPart(ESM::PartReferenceType::PRT_RForearm);
removeIndividualPart(ESM::PartReferenceType::PRT_RWrist);
}
} }
void VRAnimation::setPointForward(bool enabled) void VRAnimation::setPointForward(bool enabled)

View file

@ -46,14 +46,13 @@ public:
/// to indicate the facing orientation of the character. /// to indicate the facing orientation of the character.
virtual void setPitchFactor(float factor) { mPitchFactor = factor; } virtual void setPitchFactor(float factor) { mPitchFactor = factor; }
/// Overriden to always be VM_VRHeadless /// Overriden to always be a variant of VM_VR*
virtual void setViewMode(ViewMode viewMode); virtual void setViewMode(ViewMode viewMode);
/// Overriden to include VR modifications /// Overriden to include VR modifications
virtual void updateParts(); virtual void updateParts();
/// Overrides finger animations to point forward /// Overrides finger animations to point forward
/// (Used to visualize direction of activation action)
void setPointForward(bool enabled); void setPointForward(bool enabled);
bool canPlaceObject(); bool canPlaceObject();

View file

@ -293,6 +293,18 @@ namespace MWWorld
return MWBase::Environment::get().getMechanicsManager()->getActorsFighting(getPlayer()).size() != 0; return MWBase::Environment::get().getMechanicsManager()->getActorsFighting(getPlayer()).size() != 0;
} }
bool Player::isDisabled()
{
bool disabled = false;
auto ptr = getPlayer();
const MWWorld::Class& cls = ptr.getClass();
auto& stats = cls.getCreatureStats(ptr);
disabled |= stats.getKnockedDown();
disabled |= stats.getMagicEffects().get(ESM::MagicEffect::Paralyze).getMagnitude() > 0.f;
disabled |= stats.isDead();
return disabled;
}
bool Player::enemiesNearby() bool Player::enemiesNearby()
{ {
return MWBase::Environment::get().getMechanicsManager()->getEnemiesNearby(getPlayer()).size() != 0; return MWBase::Environment::get().getMechanicsManager()->getEnemiesNearby(getPlayer()).size() != 0;

View file

@ -127,6 +127,9 @@ namespace MWWorld
///Checks all nearby actors to see if anyone has an aipackage against you ///Checks all nearby actors to see if anyone has an aipackage against you
bool isInCombat(); bool isInCombat();
///Checks if the player is currently in a state where he cannot act
bool isDisabled();
bool enemiesNearby(); bool enemiesNearby();
void clear(); void clear();