1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-03-29 13:20:35 +00:00

more improvements

This commit is contained in:
mrcheko 2014-01-01 21:40:31 +02:00
parent a8fb1ae51c
commit 09a0a69b04
4 changed files with 124 additions and 54 deletions

View File

@ -81,6 +81,7 @@ static const std::string sHitList[] = {
"hit3" , "hit3" ,
"hit4" , "hit4" ,
"hit5" , "hit5" ,
"knockdown" ,
}; };
static const int sHitListSize = sizeof(sHitList)/sizeof(sHitList[0]); static const int sHitListSize = sizeof(sHitList)/sizeof(sHitList[0]);
@ -161,23 +162,23 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat
{ {
if(MWWorld::Class::get(mPtr).getCreatureStats(mPtr).getAttacked()) if(MWWorld::Class::get(mPtr).getCreatureStats(mPtr).getAttacked())
{ {
mHitState = CharState_Hit;
MWWorld::Class::get(mPtr).getCreatureStats(mPtr).setAttacked(false); MWWorld::Class::get(mPtr).getCreatureStats(mPtr).setAttacked(false);
if(!mAnimation->isPlaying(mCurrentHit)) 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 = "knockdown"; mCurrentHit = sHitList[sHitListSize-1]; //knockdown animation
else else
{ {
int iHit = rand() % sHitListSize; 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(!mAnimation->isPlaying(mCurrentHit)) else if(mHitState != CharState_None && !mAnimation->isPlaying(mCurrentHit))
{ {
mCurrentHit.erase(); mCurrentHit.erase();
mHitState = CharState_None; mHitState = CharState_None;
@ -458,9 +459,27 @@ void CharacterController::updatePtr(const MWWorld::Ptr &ptr)
} }
void CharacterController::playWeaponAnim(const std::string& start, const std::string& stop,
float speed, bool autoDisable, bool disablePrevious, float startpoint, bool currentWeapon)
{
std::string weapgroup;
if (currentWeapon)
weapgroup = mCurrentWeapon;
else
getWeaponGroup(mWeaponType, weapgroup);
if (disablePrevious)
mAnimation->disable(weapgroup);
mAnimation->play(weapgroup, Priority_Weapon,
MWRender::Animation::Group_All, autoDisable,
speed, start, stop,
startpoint, 0);
}
bool CharacterController::updateNpcState(bool onground, bool inwater, bool isrunning, bool sneak) bool CharacterController::updateNpcState(bool onground, bool inwater, bool isrunning, bool sneak)
{ {
const MWWorld::Class &cls = MWWorld::Class::get(mPtr); const MWWorld::Class &cls = MWWorld::Class::get(mPtr);
NpcStats &stats = cls.getNpcStats(mPtr); NpcStats &stats = cls.getNpcStats(mPtr);
WeaponType weaptype = WeapType_None; WeaponType weaptype = WeapType_None;
MWWorld::InventoryStore &inv = cls.getInventoryStore(mPtr); MWWorld::InventoryStore &inv = cls.getInventoryStore(mPtr);
@ -490,6 +509,7 @@ bool CharacterController::updateNpcState(bool onground, bool inwater, bool isrun
{ {
getWeaponGroup(weaptype, weapgroup); getWeaponGroup(weaptype, weapgroup);
mAnimation->showWeapons(false); mAnimation->showWeapons(false);
mAnimation->play(weapgroup, Priority_Weapon, mAnimation->play(weapgroup, Priority_Weapon,
MWRender::Animation::Group_UpperBody, true, MWRender::Animation::Group_UpperBody, true,
1.0f, "equip start", "equip stop", 0.0f, 0); 1.0f, "equip start", "equip stop", 0.0f, 0);
@ -642,7 +662,14 @@ bool CharacterController::updateNpcState(bool onground, bool inwater, bool isrun
{ {
if(mWeaponType == WeapType_Crossbow || mWeaponType == WeapType_BowAndArrow || if(mWeaponType == WeapType_Crossbow || mWeaponType == WeapType_BowAndArrow ||
mWeaponType == WeapType_ThowWeapon) mWeaponType == WeapType_ThowWeapon)
{
mAttackType = "shoot"; mAttackType = "shoot";
mAnimation->play(mCurrentWeapon, Priority_Weapon,
MWRender::Animation::Group_UpperBody, false,
weapSpeed, mAttackType+" start", mAttackType+" attach",
0.0f, 0);
mUpperBodyState = UpperCharState_StartToAttach;
}
else else
{ {
int attackType = stats.getAttackType(); int attackType = stats.getAttackType();
@ -655,13 +682,13 @@ bool CharacterController::updateNpcState(bool onground, bool inwater, bool isrun
mAttackType = "slash"; mAttackType = "slash";
else else
mAttackType = "thrust"; mAttackType = "thrust";
}
mAnimation->play(mCurrentWeapon, Priority_Weapon, mAnimation->play(mCurrentWeapon, Priority_Weapon,
MWRender::Animation::Group_UpperBody, false, MWRender::Animation::Group_UpperBody, false,
weapSpeed, mAttackType+" start", mAttackType+" min attack", weapSpeed, mAttackType+" start", mAttackType+" min attack",
0.0f, 0); 0.0f, 0);
mUpperBodyState = UpperCharState_StartToMinAttack; mUpperBodyState = UpperCharState_StartToMinAttack;
}
} }
} }
animPlaying = mAnimation->getInfo(mCurrentWeapon, &complete); animPlaying = mAnimation->getInfo(mCurrentWeapon, &complete);
@ -711,79 +738,105 @@ bool CharacterController::updateNpcState(bool onground, bool inwater, bool isrun
mUpperBodyState == UpperCharState_CastingSpell) mUpperBodyState == UpperCharState_CastingSpell)
{ {
mUpperBodyState = UpperCharState_WeapEquiped; mUpperBodyState = UpperCharState_WeapEquiped;
//don't allow to continue playing hit animation after actor had attacked during it
if(mHitState != CharState_None) if(mHitState != CharState_None) //don't allow to continue playing hit animation after actor had attacked during it
{ {
mAnimation->disable(mCurrentHit); mAnimation->changeGroups(mCurrentHit, MWRender::Animation::Group_LowerBody);
mCurrentHit.clear(); mCurrentHit.clear();
mHitState = CharState_None; mHitState = CharState_None;
} }
} }
else if(mUpperBodyState == UpperCharState_UnEquipingWeap) else if(mUpperBodyState == UpperCharState_UnEquipingWeap)
mUpperBodyState = UpperCharState_Nothing; mUpperBodyState = UpperCharState_Nothing;
} }
else if(complete >= 1.0f) else if(complete >= 1.0f)
{ {
if(mUpperBodyState == UpperCharState_StartToMinAttack) std::string start, stop;
switch(mUpperBodyState)
{ {
mAnimation->disable(mCurrentWeapon); case UpperCharState_StartToMinAttack:
mAnimation->play(mCurrentWeapon, Priority_Weapon, start = mAttackType+" min attack";
MWRender::Animation::Group_UpperBody, false, stop = mAttackType+" max attack";
weapSpeed, mAttackType+" min attack", mAttackType+" max attack", mUpperBodyState = UpperCharState_MinAttackToMaxAttack;
0.0f, 0); break;
mUpperBodyState = UpperCharState_MinAttackToMaxAttack; case UpperCharState_StartToAttach: //only bows, crossbows, throwing weapons here
start = mAttackType+" attach";
stop = mAttackType+" min attack";
mUpperBodyState = UpperCharState_StartToMinAttack;
break;
case UpperCharState_MaxAttackToMinHit:
if(mAttackType == "shoot")
{
start = mAttackType+" min hit";
stop = mAttackType+" release";
}
else
{
start = mAttackType+" min hit";
stop = mAttackType+" hit";
}
mUpperBodyState = UpperCharState_MinHitToHit;
break;
case UpperCharState_MinHitToHit:
if(mAttackType == "shoot")
{
start = mAttackType+" follow start";
stop = mAttackType+" follow stop";
}
else
{
float str = stats.getAttackStrength();
start = mAttackType+((str < 0.5f) ? " small follow start"
: (str < 1.0f) ? " medium follow start"
: " large follow start");
stop = mAttackType+((str < 0.5f) ? " small follow stop"
: (str < 1.0f) ? " medium follow stop"
: " large follow stop");
}
mUpperBodyState = UpperCharState_FollowStartToFollowStop;
break;
default:
break;
} }
else if(mUpperBodyState == UpperCharState_MaxAttackToMinHit)
if(!start.empty())
{ {
mAnimation->disable(mCurrentWeapon); mAnimation->disable(mCurrentWeapon);
if(mAttackType == "shoot") if (mUpperBodyState == UpperCharState_FollowStartToFollowStop)
mAnimation->play(mCurrentWeapon, Priority_Weapon,
MWRender::Animation::Group_UpperBody, false,
weapSpeed, mAttackType+" min hit", mAttackType+" follow start",
0.0f, 0);
else
mAnimation->play(mCurrentWeapon, Priority_Weapon,
MWRender::Animation::Group_UpperBody, false,
weapSpeed, mAttackType+" min hit", mAttackType+" hit",
0.0f, 0);
mUpperBodyState = UpperCharState_MinHitToHit;
}
else if(mUpperBodyState == UpperCharState_MinHitToHit)
{
mAnimation->disable(mCurrentWeapon);
if(mAttackType == "shoot")
mAnimation->play(mCurrentWeapon, Priority_Weapon,
MWRender::Animation::Group_UpperBody, true,
weapSpeed, mAttackType+" follow start", mAttackType+" follow stop",
0.0f, 0);
else
{
float str = stats.getAttackStrength();
std::string start = mAttackType+((str < 0.5f) ? " small follow start"
: (str < 1.0f) ? " medium follow start"
: " large follow start");
std::string stop = mAttackType+((str < 0.5f) ? " small follow stop"
: (str < 1.0f) ? " medium follow stop"
: " large follow stop");
mAnimation->play(mCurrentWeapon, Priority_Weapon, mAnimation->play(mCurrentWeapon, Priority_Weapon,
MWRender::Animation::Group_UpperBody, true, MWRender::Animation::Group_UpperBody, true,
weapSpeed, start, stop, 0.0f, 0); weapSpeed, start, stop, 0.0f, 0);
} else
mUpperBodyState = UpperCharState_FollowStartToFollowStop; mAnimation->play(mCurrentWeapon, Priority_Weapon,
MWRender::Animation::Group_UpperBody, false,
weapSpeed, start, stop, 0.0f, 0);
} }
} }
//if playing combat animation and lowerbody is not busy switch to whole body animation
if(weaptype != WeaponType::WeapType_None && complete>0.0f)
{
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);
if(torch != inv.end() && torch->getTypeName() == typeid(ESM::Light).name() if(torch != inv.end() && torch->getTypeName() == typeid(ESM::Light).name()
&& mWeaponType != WeapType_Spell && mWeaponType != WeapType_HandToHand) && mWeaponType != WeapType_Spell && mWeaponType != WeapType_HandToHand)
{ {
mAnimation->play("torch", Priority_Torch, MWRender::Animation::Group_LeftArm, mAnimation->play("torch", Priority_Torch, MWRender::Animation::Group_LeftArm,
false, 1.0f, "start", "stop", 0.0f, (~(size_t)0)); false, 1.0f, "start", "stop", 0.0f, (~(size_t)0));
} }
else if (mAnimation->isPlaying("torch")) else if (mAnimation->isPlaying("torch"))
{ {
mAnimation->disable("torch"); mAnimation->disable("torch");
} }
return forcestateupdate; return forcestateupdate;

View File

@ -114,6 +114,7 @@ enum UpperBodyCharacterState {
UpperCharState_UnEquipingWeap, UpperCharState_UnEquipingWeap,
UpperCharState_WeapEquiped, UpperCharState_WeapEquiped,
UpperCharState_StartToMinAttack, UpperCharState_StartToMinAttack,
UpperCharState_StartToAttach,
UpperCharState_MinAttackToMaxAttack, UpperCharState_MinAttackToMaxAttack,
UpperCharState_MaxAttackToMinHit, UpperCharState_MaxAttackToMinHit,
UpperCharState_MinHitToHit, UpperCharState_MinHitToHit,
@ -175,6 +176,8 @@ class CharacterController
void clearAnimQueue(); void clearAnimQueue();
bool updateNpcState(bool onground, bool inwater, bool isrunning, bool sneak); bool updateNpcState(bool onground, bool inwater, bool isrunning, bool sneak);
void playWeaponAnim(const std::string& start, const std::string& stop,
float speed = 1.0f, bool autoDisable = true, bool disablePrevious = false, float startpoint = 0.0f, bool currentWeapon = true);
void updateVisibility(); void updateVisibility();

View File

@ -672,7 +672,20 @@ void Animation::handleTextKey(AnimState &state, const std::string &groupname, co
MWBase::Environment::get().getWorld()->castSpell(mPtr); MWBase::Environment::get().getWorld()->castSpell(mPtr);
} }
void Animation::changeGroups(const std::string &groupname, int groups)
{
AnimStateMap::iterator stateiter = mStates.begin();
stateiter = mStates.find(groupname);
if(stateiter != mStates.end())
{
if(stateiter->second.mGroups != groups)
{
stateiter->second.mGroups = groups;
resetActiveGroups();
}
return;
}
}
void Animation::play(const std::string &groupname, int priority, int groups, bool autodisable, float speedmult, const std::string &start, const std::string &stop, float startpoint, size_t loops) void Animation::play(const std::string &groupname, int priority, int groups, bool autodisable, float speedmult, const std::string &start, const std::string &stop, float startpoint, size_t loops)
{ {
if(!mSkelBase || mAnimSources.empty()) if(!mSkelBase || mAnimSources.empty())

View File

@ -272,6 +272,7 @@ public:
* \param groupname Animation group to disable. * \param groupname Animation group to disable.
*/ */
void disable(const std::string &groupname); void disable(const std::string &groupname);
void changeGroups(const std::string &groupname, int group);
/** Retrieves the velocity (in units per second) that the animation will move. */ /** Retrieves the velocity (in units per second) that the animation will move. */
float getVelocity(const std::string &groupname) const; float getVelocity(const std::string &groupname) const;