From 46519062d3614f2d5259bb34bc781b22a4d4f263 Mon Sep 17 00:00:00 2001 From: mrcheko Date: Wed, 8 Jan 2014 16:05:14 +0200 Subject: [PATCH] hit recoils/knockdowns feature --- apps/openmw/mwclass/npc.cpp | 2 +- apps/openmw/mwmechanics/character.cpp | 57 ++++++++------------------- apps/openmw/mwmechanics/character.hpp | 1 + apps/openmw/mwrender/animation.cpp | 14 ------- apps/openmw/mwrender/animation.hpp | 1 - 5 files changed, 19 insertions(+), 56 deletions(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index b23cb08142..4fb00a032a 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -614,7 +614,7 @@ namespace MWClass // something, alert the character controller, scripts, etc. MWBase::Environment::get().getDialogueManager()->say(ptr, "hit"); - getCreatureStats(ptr).setAttacked(true); + getCreatureStats(ptr).setAttacked(true);//used in CharacterController if(object.isEmpty()) { diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index d93ae9519c..a4b4f24717 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -158,6 +158,7 @@ public: 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).getCreatureStats(mPtr).getAttacked()) @@ -166,19 +167,20 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat if(mHitState == CharState_None) { - mHitState = CharState_Hit; if(mJumpState != JumpState_None && !MWBase::Environment::get().getWorld()->isFlying(mPtr) && !MWBase::Environment::get().getWorld()->isSwimming(mPtr) ) { - mCurrentHit = sHitList[sHitListSize-1]; //knockdown animation mHitState = CharState_KnockDown; + mCurrentHit = sHitList[sHitListSize-1]; + mAnimation->play(mCurrentHit, Priority_Knockdown, MWRender::Animation::Group_All, true, 1, "start", "stop", 0.0f, 0); } else { + mHitState = CharState_Hit; int iHit = rand() % (sHitListSize-1); 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)) @@ -249,8 +251,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat else { mAnimation->disable(mCurrentJump); - //mCurrentJump.clear(); - mCurrentJump = jump; + mCurrentJump.clear(); mAnimation->play(jump, Priority_Jump, jumpgroup, true, 1.0f, "loop stop", "stop", 0.0f, 0); } @@ -685,7 +686,7 @@ bool CharacterController::updateNpcState(bool onground, bool inwater, bool isrun else { animPlaying = mAnimation->getInfo(mCurrentWeapon, &complete); - if(mUpperBodyState == UpperCharState_MinAttackToMaxAttack) + if(mUpperBodyState == UpperCharState_MinAttackToMaxAttack && mHitState != CharState_KnockDown) { if(mAttackType != "shoot") { @@ -710,7 +711,7 @@ bool CharacterController::updateNpcState(bool onground, bool inwater, bool isrun } } stats.setAttackStrength(complete); - + mAnimation->disable(mCurrentWeapon); mAnimation->play(mCurrentWeapon, Priority_Weapon, MWRender::Animation::Group_UpperBody, false, @@ -718,6 +719,11 @@ bool CharacterController::updateNpcState(bool onground, bool inwater, bool isrun 1.0f-complete, 0); mUpperBodyState = UpperCharState_MaxAttackToMinHit; } + else if (mHitState == CharState_KnockDown) + { + mUpperBodyState = UpperCharState_WeapEquiped; + mAnimation->disable(mCurrentWeapon); + } } if(!animPlaying) @@ -728,7 +734,7 @@ bool CharacterController::updateNpcState(bool onground, bool inwater, bool isrun { mUpperBodyState = UpperCharState_WeapEquiped; //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); //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"; mUpperBodyState = UpperCharState_MinAttackToMaxAttack; 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: if(mAttackType == "shoot") { @@ -803,23 +803,6 @@ bool CharacterController::updateNpcState(bool onground, bool inwater, bool isrun 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); @@ -1002,14 +985,8 @@ void CharacterController::update(float duration) } else { - if(!(vec.z > 0.0f)) - { - if(!mAnimation->isPlaying(mCurrentJump)) - { - mJumpState = JumpState_None; - mCurrentJump.clear(); - } - } + if(!(vec.z > 0.0f)) + mJumpState = JumpState_None; vec.z = 0.0f; 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); 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->queueMovement(mPtr, vec); diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index b7c29e9ef3..438f542f02 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -30,6 +30,7 @@ enum Priority { Priority_Movement, Priority_Hit, Priority_Weapon, + Priority_Knockdown, Priority_Torch, Priority_Death, diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 3e682399e6..8ce751286a 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -562,7 +562,6 @@ void Animation::updatePosition(float oldtime, float newtime, Ogre::Vector3 &posi /* Translate the accumulation root back to compensate for the move. */ 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) @@ -852,7 +851,6 @@ void Animation::disable(const std::string &groupname) Ogre::Vector3 Animation::runAnimation(float duration) { Ogre::Vector3 movement(0.0f); - mAccumRootPosUpd = false; AnimStateMap::iterator stateiter = mStates.begin(); while(stateiter != mStates.end()) { @@ -946,18 +944,6 @@ Ogre::Vector3 Animation::runAnimation(float 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; } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 013b494003..f5f79dd72b 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -128,7 +128,6 @@ protected: NifOgre::ObjectScenePtr mObjectRoot; AnimSourceList mAnimSources; Ogre::Node *mAccumRoot; - bool mAccumRootPosUpd; Ogre::Node *mNonAccumRoot; NifOgre::NodeTargetValue *mNonAccumCtrl; Ogre::Vector3 mAccumulate;