1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-01-20 07:23:51 +00:00

hit recoils/knockdowns feature

This commit is contained in:
mrcheko 2014-01-08 16:05:14 +02:00
parent 2591ff2d5a
commit 46519062d3
5 changed files with 19 additions and 56 deletions

View file

@ -614,7 +614,7 @@ namespace MWClass
// something, alert the character controller, scripts, etc. // something, alert the character controller, scripts, etc.
MWBase::Environment::get().getDialogueManager()->say(ptr, "hit"); MWBase::Environment::get().getDialogueManager()->say(ptr, "hit");
getCreatureStats(ptr).setAttacked(true); getCreatureStats(ptr).setAttacked(true);//used in CharacterController
if(object.isEmpty()) if(object.isEmpty())
{ {

View file

@ -158,6 +158,7 @@ public:
void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterState movement, bool force) void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterState movement, bool force)
{ {
//hit recoils/knockdown animations handling
if(MWWorld::Class::get(mPtr).isActor()) if(MWWorld::Class::get(mPtr).isActor())
{ {
if(MWWorld::Class::get(mPtr).getCreatureStats(mPtr).getAttacked()) if(MWWorld::Class::get(mPtr).getCreatureStats(mPtr).getAttacked())
@ -166,19 +167,20 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat
if(mHitState == CharState_None) if(mHitState == CharState_None)
{ {
mHitState = CharState_Hit;
if(mJumpState != JumpState_None && !MWBase::Environment::get().getWorld()->isFlying(mPtr) if(mJumpState != JumpState_None && !MWBase::Environment::get().getWorld()->isFlying(mPtr)
&& !MWBase::Environment::get().getWorld()->isSwimming(mPtr) ) && !MWBase::Environment::get().getWorld()->isSwimming(mPtr) )
{ {
mCurrentHit = sHitList[sHitListSize-1]; //knockdown animation
mHitState = CharState_KnockDown; mHitState = CharState_KnockDown;
mCurrentHit = sHitList[sHitListSize-1];
mAnimation->play(mCurrentHit, Priority_Knockdown, MWRender::Animation::Group_All, true, 1, "start", "stop", 0.0f, 0);
} }
else else
{ {
mHitState = CharState_Hit;
int iHit = rand() % (sHitListSize-1); int iHit = rand() % (sHitListSize-1);
mCurrentHit = sHitList[iHit]; mCurrentHit = sHitList[iHit];
mAnimation->play(mCurrentHit, Priority_Hit, MWRender::Animation::Group_All, true, 1, "start", "stop", 0.0f, 0);
} }
mAnimation->play(mCurrentHit, Priority_Hit, MWRender::Animation::Group_All, true, 1, "start", "stop", 0.0f, 0);
} }
} }
else if(mHitState != CharState_None && !mAnimation->isPlaying(mCurrentHit)) else if(mHitState != CharState_None && !mAnimation->isPlaying(mCurrentHit))
@ -249,8 +251,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat
else else
{ {
mAnimation->disable(mCurrentJump); mAnimation->disable(mCurrentJump);
//mCurrentJump.clear(); mCurrentJump.clear();
mCurrentJump = jump;
mAnimation->play(jump, Priority_Jump, jumpgroup, true, mAnimation->play(jump, Priority_Jump, jumpgroup, true,
1.0f, "loop stop", "stop", 0.0f, 0); 1.0f, "loop stop", "stop", 0.0f, 0);
} }
@ -685,7 +686,7 @@ bool CharacterController::updateNpcState(bool onground, bool inwater, bool isrun
else else
{ {
animPlaying = mAnimation->getInfo(mCurrentWeapon, &complete); animPlaying = mAnimation->getInfo(mCurrentWeapon, &complete);
if(mUpperBodyState == UpperCharState_MinAttackToMaxAttack) if(mUpperBodyState == UpperCharState_MinAttackToMaxAttack && mHitState != CharState_KnockDown)
{ {
if(mAttackType != "shoot") if(mAttackType != "shoot")
{ {
@ -710,7 +711,7 @@ bool CharacterController::updateNpcState(bool onground, bool inwater, bool isrun
} }
} }
stats.setAttackStrength(complete); stats.setAttackStrength(complete);
mAnimation->disable(mCurrentWeapon); mAnimation->disable(mCurrentWeapon);
mAnimation->play(mCurrentWeapon, Priority_Weapon, mAnimation->play(mCurrentWeapon, Priority_Weapon,
MWRender::Animation::Group_UpperBody, false, MWRender::Animation::Group_UpperBody, false,
@ -718,6 +719,11 @@ bool CharacterController::updateNpcState(bool onground, bool inwater, bool isrun
1.0f-complete, 0); 1.0f-complete, 0);
mUpperBodyState = UpperCharState_MaxAttackToMinHit; mUpperBodyState = UpperCharState_MaxAttackToMinHit;
} }
else if (mHitState == CharState_KnockDown)
{
mUpperBodyState = UpperCharState_WeapEquiped;
mAnimation->disable(mCurrentWeapon);
}
} }
if(!animPlaying) if(!animPlaying)
@ -728,7 +734,7 @@ bool CharacterController::updateNpcState(bool onground, bool inwater, bool isrun
{ {
mUpperBodyState = UpperCharState_WeapEquiped; mUpperBodyState = UpperCharState_WeapEquiped;
//don't allow to continue playing hit animation on UpperBody after actor had attacked during it //don't allow to continue playing hit animation on UpperBody after actor had attacked during it
if(mHitState != CharState_None) if(mHitState == CharState_Hit)
{ {
mAnimation->changeGroups(mCurrentHit, MWRender::Animation::Group_LowerBody); mAnimation->changeGroups(mCurrentHit, MWRender::Animation::Group_LowerBody);
//commenting out following 2 lines will give a bit different combat dynamics(slower) //commenting out following 2 lines will give a bit different combat dynamics(slower)
@ -749,12 +755,6 @@ bool CharacterController::updateNpcState(bool onground, bool inwater, bool isrun
stop = mAttackType+" max attack"; stop = mAttackType+" max attack";
mUpperBodyState = UpperCharState_MinAttackToMaxAttack; mUpperBodyState = UpperCharState_MinAttackToMaxAttack;
break; break;
/*case UpperCharState_MinAttackToMaxAttack:
if(!mAnimation->isPlaying(mCurrentWeapon))
mAnimation->play(mCurrentWeapon, Priority_Weapon,
MWRender::Animation::Group_UpperBody, false,
1e-9f, mAttackType+" min attack", mAttackType+" max attack", 0.99f, ~0ul);
break;*/
case UpperCharState_MaxAttackToMinHit: case UpperCharState_MaxAttackToMinHit:
if(mAttackType == "shoot") if(mAttackType == "shoot")
{ {
@ -803,23 +803,6 @@ bool CharacterController::updateNpcState(bool onground, bool inwater, bool isrun
weapSpeed, start, stop, 0.0f, 0); weapSpeed, start, stop, 0.0f, 0);
} }
} }
//if playing combat animation and lowerbody is not busy switch to whole body animation
if((weaptype != WeapType_None || UpperCharState_UnEquipingWeap) && animPlaying)
{
if( mMovementState != CharState_None ||
mJumpState != JumpState_None ||
mHitState != CharState_None ||
MWBase::Environment::get().getWorld()->isSwimming(mPtr) ||
cls.getStance(mPtr, MWWorld::Class::Sneak))
{
mAnimation->changeGroups(mCurrentWeapon, MWRender::Animation::Group_UpperBody);
}
else
{
mAnimation->changeGroups(mCurrentWeapon, MWRender::Animation::Group_All);
}
}
MWWorld::ContainerStoreIterator torch = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft); MWWorld::ContainerStoreIterator torch = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft);
@ -1002,14 +985,8 @@ void CharacterController::update(float duration)
} }
else else
{ {
if(!(vec.z > 0.0f)) if(!(vec.z > 0.0f))
{ mJumpState = JumpState_None;
if(!mAnimation->isPlaying(mCurrentJump))
{
mJumpState = JumpState_None;
mCurrentJump.clear();
}
}
vec.z = 0.0f; vec.z = 0.0f;
if(std::abs(vec.x/2.0f) > std::abs(vec.y)) if(std::abs(vec.x/2.0f) > std::abs(vec.y))
@ -1076,7 +1053,7 @@ void CharacterController::update(float duration)
rot *= duration * Ogre::Math::RadiansToDegrees(1.0f); rot *= duration * Ogre::Math::RadiansToDegrees(1.0f);
world->rotateObject(mPtr, rot.x, rot.y, rot.z, true); world->rotateObject(mPtr, rot.x, rot.y, rot.z, true);
} }
else else //avoid z-rotating for knockdown
world->rotateObject(mPtr, rot.x, rot.y, 0.0f, true); world->rotateObject(mPtr, rot.x, rot.y, 0.0f, true);
world->queueMovement(mPtr, vec); world->queueMovement(mPtr, vec);

View file

@ -30,6 +30,7 @@ enum Priority {
Priority_Movement, Priority_Movement,
Priority_Hit, Priority_Hit,
Priority_Weapon, Priority_Weapon,
Priority_Knockdown,
Priority_Torch, Priority_Torch,
Priority_Death, Priority_Death,

View file

@ -562,7 +562,6 @@ void Animation::updatePosition(float oldtime, float newtime, Ogre::Vector3 &posi
/* Translate the accumulation root back to compensate for the move. */ /* Translate the accumulation root back to compensate for the move. */
mAccumRoot->setPosition(-off); mAccumRoot->setPosition(-off);
mAccumRootPosUpd=true;
} }
bool Animation::reset(AnimState &state, const NifOgre::TextKeyMap &keys, const std::string &groupname, const std::string &start, const std::string &stop, float startpoint) bool Animation::reset(AnimState &state, const NifOgre::TextKeyMap &keys, const std::string &groupname, const std::string &start, const std::string &stop, float startpoint)
@ -852,7 +851,6 @@ void Animation::disable(const std::string &groupname)
Ogre::Vector3 Animation::runAnimation(float duration) Ogre::Vector3 Animation::runAnimation(float duration)
{ {
Ogre::Vector3 movement(0.0f); Ogre::Vector3 movement(0.0f);
mAccumRootPosUpd = false;
AnimStateMap::iterator stateiter = mStates.begin(); AnimStateMap::iterator stateiter = mStates.begin();
while(stateiter != mStates.end()) while(stateiter != mStates.end())
{ {
@ -946,18 +944,6 @@ Ogre::Vector3 Animation::runAnimation(float duration)
updateEffects(duration); updateEffects(duration);
if (!mAccumRootPosUpd)
{
for(stateiter = mStates.begin();stateiter != mStates.end(); stateiter++)
{
if(mNonAccumCtrl && stateiter->first == mAnimationValuePtr[0]->getAnimName())
{
updatePosition(stateiter->second.mTime, stateiter->second.mTime, movement);
break;
}
}
}
return movement; return movement;
} }

View file

@ -128,7 +128,6 @@ protected:
NifOgre::ObjectScenePtr mObjectRoot; NifOgre::ObjectScenePtr mObjectRoot;
AnimSourceList mAnimSources; AnimSourceList mAnimSources;
Ogre::Node *mAccumRoot; Ogre::Node *mAccumRoot;
bool mAccumRootPosUpd;
Ogre::Node *mNonAccumRoot; Ogre::Node *mNonAccumRoot;
NifOgre::NodeTargetValue<Ogre::Real> *mNonAccumCtrl; NifOgre::NodeTargetValue<Ogre::Real> *mNonAccumCtrl;
Ogre::Vector3 mAccumulate; Ogre::Vector3 mAccumulate;