mirror of
https://github.com/OpenMW/openmw.git
synced 2025-01-21 10:53:53 +00:00
Consolidate refreshHitRecoilAnims
This commit is contained in:
parent
a105ba14e4
commit
2c3d385672
1 changed files with 113 additions and 105 deletions
|
@ -161,6 +161,26 @@ std::string deathStateToAnimGroup(MWMechanics::CharacterState state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Converts a hit state to its equivalent animation group as long as it is a hit state.
|
||||||
|
std::string hitStateToAnimGroup(MWMechanics::CharacterState state)
|
||||||
|
{
|
||||||
|
using namespace MWMechanics;
|
||||||
|
switch (state)
|
||||||
|
{
|
||||||
|
case CharState_SwimHit: return "swimhit";
|
||||||
|
case CharState_SwimKnockDown: return "swimknockdown";
|
||||||
|
case CharState_SwimKnockOut: return "swimknockout";
|
||||||
|
|
||||||
|
case CharState_Hit: return "hit";
|
||||||
|
case CharState_KnockDown: return "knockdown";
|
||||||
|
case CharState_KnockOut: return "knockout";
|
||||||
|
|
||||||
|
case CharState_Block: return "shield";
|
||||||
|
|
||||||
|
default: return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
float getFallDamage(const MWWorld::Ptr& ptr, float fallHeight)
|
float getFallDamage(const MWWorld::Ptr& ptr, float fallHeight)
|
||||||
{
|
{
|
||||||
MWBase::World *world = MWBase::Environment::get().getWorld();
|
MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||||
|
@ -211,125 +231,114 @@ std::string CharacterController::chooseRandomGroup (const std::string& prefix, i
|
||||||
|
|
||||||
void CharacterController::refreshHitRecoilAnims(CharacterState& idle)
|
void CharacterController::refreshHitRecoilAnims(CharacterState& idle)
|
||||||
{
|
{
|
||||||
const auto world = MWBase::Environment::get().getWorld();
|
|
||||||
auto& charClass = mPtr.getClass();
|
auto& charClass = mPtr.getClass();
|
||||||
|
if (!charClass.isActor())
|
||||||
|
return;
|
||||||
|
const auto world = MWBase::Environment::get().getWorld();
|
||||||
auto& stats = charClass.getCreatureStats(mPtr);
|
auto& stats = charClass.getCreatureStats(mPtr);
|
||||||
|
bool knockout = stats.getFatigue().getCurrent() < 0 || stats.getFatigue().getBase() == 0;
|
||||||
bool recovery = stats.getHitRecovery();
|
bool recovery = stats.getHitRecovery();
|
||||||
bool knockdown = stats.getKnockedDown();
|
bool knockdown = stats.getKnockedDown();
|
||||||
bool block = stats.getBlock();
|
bool block = stats.getBlock();
|
||||||
bool isSwimming = world->isSwimming(mPtr);
|
bool isSwimming = world->isSwimming(mPtr);
|
||||||
auto& prng = world->getPrng();
|
auto& prng = world->getPrng();
|
||||||
if(mHitState == CharState_None)
|
|
||||||
{
|
|
||||||
if (stats.getFatigue().getCurrent() < 0 || stats.getFatigue().getBase() == 0)
|
|
||||||
{
|
|
||||||
mTimeUntilWake = Misc::Rng::rollClosedProbability(prng) * 2 + 1; // Wake up after 1 to 3 seconds
|
|
||||||
if (isSwimming && mAnimation->hasAnimation("swimknockout"))
|
|
||||||
{
|
|
||||||
mHitState = CharState_SwimKnockOut;
|
|
||||||
mCurrentHit = "swimknockout";
|
|
||||||
mAnimation->play(mCurrentHit, Priority_Knockdown, MWRender::Animation::BlendMask_All, false, 1, "start", "stop", 0.0f, ~0ul);
|
|
||||||
}
|
|
||||||
else if (!isSwimming && mAnimation->hasAnimation("knockout"))
|
|
||||||
{
|
|
||||||
mHitState = CharState_KnockOut;
|
|
||||||
mCurrentHit = "knockout";
|
|
||||||
mAnimation->play(mCurrentHit, Priority_Knockdown, MWRender::Animation::BlendMask_All, false, 1, "start", "stop", 0.0f, ~0ul);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Knockout animations are missing. Fall back to idle animation, so target actor still can be killed via HtH.
|
|
||||||
mCurrentHit.erase();
|
|
||||||
}
|
|
||||||
|
|
||||||
stats.setKnockedDown(true);
|
if (mHitState != CharState_None)
|
||||||
}
|
|
||||||
else if (knockdown)
|
|
||||||
{
|
|
||||||
if (isSwimming && mAnimation->hasAnimation("swimknockdown"))
|
|
||||||
{
|
|
||||||
mHitState = CharState_SwimKnockDown;
|
|
||||||
mCurrentHit = "swimknockdown";
|
|
||||||
mAnimation->play(mCurrentHit, Priority_Knockdown, MWRender::Animation::BlendMask_All, true, 1, "start", "stop", 0.0f, 0);
|
|
||||||
}
|
|
||||||
else if (!isSwimming && mAnimation->hasAnimation("knockdown"))
|
|
||||||
{
|
|
||||||
mHitState = CharState_KnockDown;
|
|
||||||
mCurrentHit = "knockdown";
|
|
||||||
mAnimation->play(mCurrentHit, Priority_Knockdown, MWRender::Animation::BlendMask_All, true, 1, "start", "stop", 0.0f, 0);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Knockdown animation is missing. Cancel knockdown state.
|
|
||||||
stats.setKnockedDown(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (recovery)
|
|
||||||
{
|
|
||||||
std::string anim = chooseRandomGroup("swimhit");
|
|
||||||
if (isSwimming && mAnimation->hasAnimation(anim))
|
|
||||||
{
|
|
||||||
mHitState = CharState_SwimHit;
|
|
||||||
mCurrentHit = anim;
|
|
||||||
mAnimation->play(mCurrentHit, Priority_Hit, MWRender::Animation::BlendMask_All, true, 1, "start", "stop", 0.0f, 0);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
anim = chooseRandomGroup("hit");
|
|
||||||
if (mAnimation->hasAnimation(anim))
|
|
||||||
{
|
|
||||||
mHitState = CharState_Hit;
|
|
||||||
mCurrentHit = anim;
|
|
||||||
mAnimation->play(mCurrentHit, Priority_Hit, MWRender::Animation::BlendMask_All, true, 1, "start", "stop", 0.0f, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (block && mAnimation->hasAnimation("shield"))
|
|
||||||
{
|
|
||||||
mHitState = CharState_Block;
|
|
||||||
mCurrentHit = "shield";
|
|
||||||
MWRender::Animation::AnimPriority priorityBlock (Priority_Hit);
|
|
||||||
priorityBlock[MWRender::Animation::BoneGroup_LeftArm] = Priority_Block;
|
|
||||||
priorityBlock[MWRender::Animation::BoneGroup_LowerBody] = Priority_WeaponLowerBody;
|
|
||||||
mAnimation->play(mCurrentHit, priorityBlock, MWRender::Animation::BlendMask_All, true, 1, "block start", "block stop", 0.0f, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cancel upper body animations
|
|
||||||
if (isKnockedOut() || isKnockedDown())
|
|
||||||
{
|
|
||||||
if (mUpperBodyState > UpperCharState_WeapEquiped)
|
|
||||||
{
|
|
||||||
mAnimation->disable(mCurrentWeapon);
|
|
||||||
mUpperBodyState = UpperCharState_WeapEquiped;
|
|
||||||
if (mWeaponType > ESM::Weapon::None)
|
|
||||||
mAnimation->showWeapons(true);
|
|
||||||
}
|
|
||||||
else if (mUpperBodyState > UpperCharState_Nothing && mUpperBodyState < UpperCharState_WeapEquiped)
|
|
||||||
{
|
|
||||||
mAnimation->disable(mCurrentWeapon);
|
|
||||||
mUpperBodyState = UpperCharState_Nothing;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (mHitState != CharState_None)
|
|
||||||
idle = CharState_None;
|
|
||||||
}
|
|
||||||
else if(!mAnimation->isPlaying(mCurrentHit))
|
|
||||||
{
|
{
|
||||||
mCurrentHit.erase();
|
if (!mAnimation->isPlaying(mCurrentHit))
|
||||||
if (knockdown)
|
{
|
||||||
|
mHitState = CharState_None;
|
||||||
|
mCurrentHit.clear();
|
||||||
stats.setKnockedDown(false);
|
stats.setKnockedDown(false);
|
||||||
if (recovery)
|
|
||||||
stats.setHitRecovery(false);
|
stats.setHitRecovery(false);
|
||||||
if (block)
|
|
||||||
stats.setBlock(false);
|
stats.setBlock(false);
|
||||||
mHitState = CharState_None;
|
}
|
||||||
|
else if (isKnockedOut() && !knockout && mTimeUntilWake <= 0)
|
||||||
|
{
|
||||||
|
mAnimation->disable(mCurrentHit);
|
||||||
|
mAnimation->play(mCurrentHit, Priority_Knockdown, MWRender::Animation::BlendMask_All, true, 1, "loop stop", "stop", 0.0f, 0);
|
||||||
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
else if (isKnockedOut() && stats.getFatigue().getCurrent() > 0 && mTimeUntilWake <= 0)
|
|
||||||
|
if (!knockout && !knockdown && !recovery && !block)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (knockout)
|
||||||
|
mTimeUntilWake = Misc::Rng::rollClosedProbability(prng) * 2 + 1; // Wake up after 1 to 3 seconds
|
||||||
|
|
||||||
|
MWRender::Animation::AnimPriority priority(Priority_Knockdown);
|
||||||
|
bool autodisable = true;
|
||||||
|
std::string startKey = "start";
|
||||||
|
std::string stopKey = "stop";
|
||||||
|
if (knockout)
|
||||||
|
{
|
||||||
|
mHitState = isSwimming ? CharState_SwimKnockOut : CharState_KnockOut;
|
||||||
|
stats.setKnockedDown(true);
|
||||||
|
autodisable = false;
|
||||||
|
}
|
||||||
|
else if (knockdown)
|
||||||
{
|
{
|
||||||
mHitState = isSwimming ? CharState_SwimKnockDown : CharState_KnockDown;
|
mHitState = isSwimming ? CharState_SwimKnockDown : CharState_KnockDown;
|
||||||
mAnimation->disable(mCurrentHit);
|
|
||||||
mAnimation->play(mCurrentHit, Priority_Knockdown, MWRender::Animation::BlendMask_All, true, 1, "loop stop", "stop", 0.0f, 0);
|
|
||||||
}
|
}
|
||||||
|
else if (recovery)
|
||||||
|
{
|
||||||
|
mHitState = isSwimming ? CharState_SwimHit : CharState_Hit;
|
||||||
|
priority = Priority_Hit;
|
||||||
|
}
|
||||||
|
else if (block)
|
||||||
|
{
|
||||||
|
mHitState = CharState_Block;
|
||||||
|
priority = Priority_Block;
|
||||||
|
priority[MWRender::Animation::BoneGroup_LeftArm] = Priority_Block;
|
||||||
|
priority[MWRender::Animation::BoneGroup_LowerBody] = Priority_WeaponLowerBody;
|
||||||
|
startKey = "block start";
|
||||||
|
stopKey = "block stop";
|
||||||
|
}
|
||||||
|
|
||||||
|
mCurrentHit = hitStateToAnimGroup(mHitState);
|
||||||
|
|
||||||
|
if (isRecovery())
|
||||||
|
{
|
||||||
|
mCurrentHit = chooseRandomGroup(mCurrentHit);
|
||||||
|
if (mHitState == CharState_SwimHit && !mAnimation->hasAnimation(mCurrentHit))
|
||||||
|
mCurrentHit = chooseRandomGroup(hitStateToAnimGroup(CharState_Hit));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mAnimation->hasAnimation(mCurrentHit))
|
||||||
|
{
|
||||||
|
// The hit animation is missing. Reset the current hit state and immediately cancel all states as if the animation were instantaneous.
|
||||||
|
mHitState = CharState_None;
|
||||||
|
mCurrentHit.clear();
|
||||||
|
stats.setKnockedDown(false);
|
||||||
|
stats.setHitRecovery(false);
|
||||||
|
stats.setBlock(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cancel upper body animations
|
||||||
|
if (isKnockedOut() || isKnockedDown())
|
||||||
|
{
|
||||||
|
if (!mCurrentWeapon.empty())
|
||||||
|
{
|
||||||
|
mAnimation->disable(mCurrentWeapon);
|
||||||
|
mCurrentWeapon.clear();
|
||||||
|
}
|
||||||
|
if (mUpperBodyState > UpperCharState_WeapEquiped)
|
||||||
|
{
|
||||||
|
mUpperBodyState = UpperCharState_WeapEquiped;
|
||||||
|
if (mWeaponType > ESM::Weapon::None)
|
||||||
|
mAnimation->showWeapons(true);
|
||||||
|
}
|
||||||
|
else if (mUpperBodyState < UpperCharState_WeapEquiped)
|
||||||
|
{
|
||||||
|
mUpperBodyState = UpperCharState_Nothing;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mAnimation->play(mCurrentHit, priority, MWRender::Animation::BlendMask_All, autodisable, 1, startKey, stopKey, 0.0f, ~0ul);
|
||||||
|
|
||||||
|
idle = CharState_None;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CharacterController::refreshJumpAnims(const std::string& weapShortGroup, JumpingState jump, CharacterState& idle, bool force)
|
void CharacterController::refreshJumpAnims(const std::string& weapShortGroup, JumpingState jump, CharacterState& idle, bool force)
|
||||||
|
@ -689,8 +698,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat
|
||||||
if (isPersistentAnimPlaying())
|
if (isPersistentAnimPlaying())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (mPtr.getClass().isActor())
|
refreshHitRecoilAnims(idle);
|
||||||
refreshHitRecoilAnims(idle);
|
|
||||||
|
|
||||||
std::string weap;
|
std::string weap;
|
||||||
if (mWeaponType != ESM::Weapon::HandToHand || mPtr.getClass().isBipedal(mPtr))
|
if (mWeaponType != ESM::Weapon::HandToHand || mPtr.getClass().isBipedal(mPtr))
|
||||||
|
|
Loading…
Reference in a new issue