mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-20 07:23:51 +00:00
Merge remote-tracking branch 'mrcheko/master'
This commit is contained in:
commit
a7be755db0
5 changed files with 190 additions and 109 deletions
|
@ -616,6 +616,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);//used in CharacterController
|
||||||
|
|
||||||
if(object.isEmpty())
|
if(object.isEmpty())
|
||||||
{
|
{
|
||||||
|
|
|
@ -63,15 +63,25 @@ struct StateInfo {
|
||||||
const char groupname[32];
|
const char groupname[32];
|
||||||
};
|
};
|
||||||
|
|
||||||
static const StateInfo sDeathList[] = {
|
static const std::string sDeathList[] = {
|
||||||
{ CharState_Death1, "death1" },
|
"death1" ,
|
||||||
{ CharState_Death2, "death2" },
|
"death2" ,
|
||||||
{ CharState_Death3, "death3" },
|
"death3" ,
|
||||||
{ CharState_Death4, "death4" },
|
"death4" ,
|
||||||
{ CharState_Death5, "death5" },
|
"death5" ,
|
||||||
{ CharState_SwimDeath, "swimdeath" },
|
"swimdeath",
|
||||||
};
|
};
|
||||||
static const StateInfo *sDeathListEnd = &sDeathList[sizeof(sDeathList)/sizeof(sDeathList[0])];
|
static const int sDeathListSize = sizeof(sDeathList)/sizeof(sDeathList[0]);
|
||||||
|
|
||||||
|
static const std::string sHitList[] = {
|
||||||
|
"hit1" ,
|
||||||
|
"hit2" ,
|
||||||
|
"hit3" ,
|
||||||
|
"hit4" ,
|
||||||
|
"hit5" ,
|
||||||
|
"knockdown" ,
|
||||||
|
};
|
||||||
|
static const int sHitListSize = sizeof(sHitList)/sizeof(sHitList[0]);
|
||||||
|
|
||||||
static const StateInfo sMovementList[] = {
|
static const StateInfo sMovementList[] = {
|
||||||
{ CharState_WalkForward, "walkforward" },
|
{ CharState_WalkForward, "walkforward" },
|
||||||
|
@ -148,6 +158,38 @@ 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).getCreatureStats(mPtr).getAttacked())
|
||||||
|
{
|
||||||
|
MWWorld::Class::get(mPtr).getCreatureStats(mPtr).setAttacked(false);
|
||||||
|
|
||||||
|
if(mHitState == CharState_None)
|
||||||
|
{
|
||||||
|
if(mJumpState != JumpState_None && !MWBase::Environment::get().getWorld()->isFlying(mPtr)
|
||||||
|
&& !MWBase::Environment::get().getWorld()->isSwimming(mPtr) )
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(mHitState != CharState_None && !mAnimation->isPlaying(mCurrentHit))
|
||||||
|
{
|
||||||
|
mCurrentHit.erase();
|
||||||
|
mHitState = CharState_None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const WeaponInfo *weap = std::find_if(sWeaponTypeList, sWeaponTypeListEnd, FindWeaponType(mWeaponType));
|
const WeaponInfo *weap = std::find_if(sWeaponTypeList, sWeaponTypeListEnd, FindWeaponType(mWeaponType));
|
||||||
|
|
||||||
if(force || idle != mIdleState)
|
if(force || idle != mIdleState)
|
||||||
|
@ -336,6 +378,31 @@ MWWorld::ContainerStoreIterator CharacterController::getActiveWeapon(NpcStats &s
|
||||||
return inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
return inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CharacterController::playRandomDeath(float startpoint)
|
||||||
|
{
|
||||||
|
if(MWWorld::Class::get(mPtr).isNpc())
|
||||||
|
{
|
||||||
|
if(MWBase::Environment::get().getWorld()->isSwimming(mPtr))
|
||||||
|
{
|
||||||
|
mDeathState = CharState_SwimDeath;
|
||||||
|
mCurrentDeath = sDeathList[sDeathListSize-1]; //last in the list is 'swimdeath'
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int num = rand() % (sDeathListSize-1);
|
||||||
|
mDeathState = static_cast<CharacterState>(CharState_Death1 + num);
|
||||||
|
mCurrentDeath = sDeathList[num];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mDeathState = CharState_Death1;
|
||||||
|
mCurrentDeath = "death1";
|
||||||
|
}
|
||||||
|
|
||||||
|
mAnimation->play(mCurrentDeath, Priority_Death, MWRender::Animation::Group_All,
|
||||||
|
false, 1.0f, "start", "stop", 0.0f, 0);
|
||||||
|
}
|
||||||
|
|
||||||
CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim)
|
CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim)
|
||||||
: mPtr(ptr)
|
: mPtr(ptr)
|
||||||
|
@ -344,6 +411,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim
|
||||||
, mMovementState(CharState_None)
|
, mMovementState(CharState_None)
|
||||||
, mMovementSpeed(0.0f)
|
, mMovementSpeed(0.0f)
|
||||||
, mDeathState(CharState_None)
|
, mDeathState(CharState_None)
|
||||||
|
, mHitState(CharState_None)
|
||||||
, mUpperBodyState(UpperCharState_Nothing)
|
, mUpperBodyState(UpperCharState_Nothing)
|
||||||
, mJumpState(JumpState_None)
|
, mJumpState(JumpState_None)
|
||||||
, mWeaponType(WeapType_None)
|
, mWeaponType(WeapType_None)
|
||||||
|
@ -388,15 +456,10 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim
|
||||||
}
|
}
|
||||||
|
|
||||||
refreshCurrentAnims(mIdleState, mMovementState, true);
|
refreshCurrentAnims(mIdleState, mMovementState, true);
|
||||||
|
|
||||||
if(mDeathState != CharState_None)
|
if(mDeathState != CharState_None)
|
||||||
{
|
{
|
||||||
const StateInfo *state = std::find_if(sDeathList, sDeathListEnd, FindCharState(mDeathState));
|
playRandomDeath(1.0f);
|
||||||
if(state == sDeathListEnd)
|
|
||||||
throw std::runtime_error("Failed to find character state "+Ogre::StringConverter::toString(mDeathState));
|
|
||||||
|
|
||||||
mCurrentDeath = state->groupname;
|
|
||||||
mAnimation->play(mCurrentDeath, Priority_Death, MWRender::Animation::Group_All,
|
|
||||||
false, 1.0f, "start", "stop", 1.0f, 0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -410,7 +473,6 @@ void CharacterController::updatePtr(const MWWorld::Ptr &ptr)
|
||||||
mPtr = ptr;
|
mPtr = ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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);
|
||||||
|
@ -443,6 +505,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);
|
||||||
|
@ -498,7 +561,7 @@ bool CharacterController::updateNpcState(bool onground, bool inwater, bool isrun
|
||||||
bool animPlaying;
|
bool animPlaying;
|
||||||
if(stats.getAttackingOrSpell())
|
if(stats.getAttackingOrSpell())
|
||||||
{
|
{
|
||||||
if(mUpperBodyState == UpperCharState_WeapEquiped)
|
if(mUpperBodyState == UpperCharState_WeapEquiped && mHitState == CharState_None)
|
||||||
{
|
{
|
||||||
MWBase::Environment::get().getWorld()->breakInvisibility(mPtr);
|
MWBase::Environment::get().getWorld()->breakInvisibility(mPtr);
|
||||||
mAttackType.clear();
|
mAttackType.clear();
|
||||||
|
@ -617,12 +680,13 @@ bool CharacterController::updateNpcState(bool onground, bool inwater, bool isrun
|
||||||
mUpperBodyState = UpperCharState_StartToMinAttack;
|
mUpperBodyState = UpperCharState_StartToMinAttack;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
animPlaying = mAnimation->getInfo(mCurrentWeapon, &complete);
|
animPlaying = mAnimation->getInfo(mCurrentWeapon, &complete);
|
||||||
}
|
}
|
||||||
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")
|
||||||
{
|
{
|
||||||
|
@ -655,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)
|
||||||
|
@ -662,61 +731,80 @@ bool CharacterController::updateNpcState(bool onground, bool inwater, bool isrun
|
||||||
if(mUpperBodyState == UpperCharState_EquipingWeap ||
|
if(mUpperBodyState == UpperCharState_EquipingWeap ||
|
||||||
mUpperBodyState == UpperCharState_FollowStartToFollowStop ||
|
mUpperBodyState == UpperCharState_FollowStartToFollowStop ||
|
||||||
mUpperBodyState == UpperCharState_CastingSpell)
|
mUpperBodyState == UpperCharState_CastingSpell)
|
||||||
|
{
|
||||||
mUpperBodyState = UpperCharState_WeapEquiped;
|
mUpperBodyState = UpperCharState_WeapEquiped;
|
||||||
|
//don't allow to continue playing hit animation on UpperBody after actor had attacked during it
|
||||||
|
if(mHitState == CharState_Hit)
|
||||||
|
{
|
||||||
|
mAnimation->changeGroups(mCurrentHit, MWRender::Animation::Group_LowerBody);
|
||||||
|
//commenting out following 2 lines will give a bit different combat dynamics(slower)
|
||||||
|
mHitState = CharState_None;
|
||||||
|
mCurrentHit.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
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",
|
|
||||||
0.0f, 0);
|
|
||||||
mUpperBodyState = UpperCharState_MinAttackToMaxAttack;
|
mUpperBodyState = UpperCharState_MinAttackToMaxAttack;
|
||||||
}
|
break;
|
||||||
else if(mUpperBodyState == UpperCharState_MaxAttackToMinHit)
|
case UpperCharState_MaxAttackToMinHit:
|
||||||
{
|
|
||||||
mAnimation->disable(mCurrentWeapon);
|
|
||||||
if(mAttackType == "shoot")
|
if(mAttackType == "shoot")
|
||||||
mAnimation->play(mCurrentWeapon, Priority_Weapon,
|
{
|
||||||
MWRender::Animation::Group_UpperBody, false,
|
start = mAttackType+" min hit";
|
||||||
weapSpeed, mAttackType+" min hit", mAttackType+" follow start",
|
stop = mAttackType+" release";
|
||||||
0.0f, 0);
|
}
|
||||||
else
|
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);
|
start = mAttackType+" min hit";
|
||||||
|
stop = mAttackType+" hit";
|
||||||
|
}
|
||||||
|
mUpperBodyState = UpperCharState_MinHitToHit;
|
||||||
|
break;
|
||||||
|
case UpperCharState_MinHitToHit:
|
||||||
if(mAttackType == "shoot")
|
if(mAttackType == "shoot")
|
||||||
mAnimation->play(mCurrentWeapon, Priority_Weapon,
|
{
|
||||||
MWRender::Animation::Group_UpperBody, true,
|
start = mAttackType+" follow start";
|
||||||
weapSpeed, mAttackType+" follow start", mAttackType+" follow stop",
|
stop = mAttackType+" follow stop";
|
||||||
0.0f, 0);
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
float str = stats.getAttackStrength();
|
float str = stats.getAttackStrength();
|
||||||
std::string start = mAttackType+((str < 0.5f) ? " small follow start"
|
start = mAttackType+((str < 0.5f) ? " small follow start"
|
||||||
: (str < 1.0f) ? " medium follow start"
|
: (str < 1.0f) ? " medium follow start"
|
||||||
: " large follow start");
|
: " large follow start");
|
||||||
std::string stop = mAttackType+((str < 0.5f) ? " small follow stop"
|
stop = mAttackType+((str < 0.5f) ? " small follow stop"
|
||||||
: (str < 1.0f) ? " medium follow stop"
|
: (str < 1.0f) ? " medium follow stop"
|
||||||
: " large follow stop");
|
: " large follow stop");
|
||||||
|
}
|
||||||
|
mUpperBodyState = UpperCharState_FollowStartToFollowStop;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!start.empty())
|
||||||
|
{
|
||||||
|
mAnimation->disable(mCurrentWeapon);
|
||||||
|
if (mUpperBodyState == UpperCharState_FollowStartToFollowStop)
|
||||||
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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)
|
||||||
|
@ -764,6 +852,8 @@ void CharacterController::update(float duration)
|
||||||
bool sneak = cls.getStance(mPtr, MWWorld::Class::Sneak);
|
bool sneak = cls.getStance(mPtr, MWWorld::Class::Sneak);
|
||||||
bool flying = world->isFlying(mPtr);
|
bool flying = world->isFlying(mPtr);
|
||||||
Ogre::Vector3 vec = cls.getMovementVector(mPtr);
|
Ogre::Vector3 vec = cls.getMovementVector(mPtr);
|
||||||
|
if(mHitState != CharState_None && mJumpState == JumpState_None)
|
||||||
|
vec = Ogre::Vector3(0.0f);
|
||||||
Ogre::Vector3 rot = cls.getRotationVector(mPtr);
|
Ogre::Vector3 rot = cls.getRotationVector(mPtr);
|
||||||
mMovementSpeed = cls.getSpeed(mPtr);
|
mMovementSpeed = cls.getSpeed(mPtr);
|
||||||
|
|
||||||
|
@ -776,6 +866,7 @@ void CharacterController::update(float duration)
|
||||||
|
|
||||||
isrunning = isrunning && std::abs(vec[0])+std::abs(vec[1]) > 0.0f;
|
isrunning = isrunning && std::abs(vec[0])+std::abs(vec[1]) > 0.0f;
|
||||||
|
|
||||||
|
|
||||||
// advance athletics
|
// advance athletics
|
||||||
if(std::abs(vec[0])+std::abs(vec[1]) > 0.0f && mPtr.getRefData().getHandle() == "player")
|
if(std::abs(vec[0])+std::abs(vec[1]) > 0.0f && mPtr.getRefData().getHandle() == "player")
|
||||||
{
|
{
|
||||||
|
@ -879,6 +970,7 @@ void CharacterController::update(float duration)
|
||||||
int realHealthLost = healthLost * (1.0f - 0.25 * fatigueTerm);
|
int realHealthLost = healthLost * (1.0f - 0.25 * fatigueTerm);
|
||||||
health.setCurrent(health.getCurrent() - realHealthLost);
|
health.setCurrent(health.getCurrent() - realHealthLost);
|
||||||
cls.getCreatureStats(mPtr).setHealth(health);
|
cls.getCreatureStats(mPtr).setHealth(health);
|
||||||
|
cls.onHit(mPtr, realHealthLost, true, MWWorld::Ptr(), MWWorld::Ptr(), true);
|
||||||
|
|
||||||
// report acrobatics progression
|
// report acrobatics progression
|
||||||
if (mPtr.getRefData().getHandle() == "player")
|
if (mPtr.getRefData().getHandle() == "player")
|
||||||
|
@ -954,13 +1046,19 @@ void CharacterController::update(float duration)
|
||||||
|
|
||||||
refreshCurrentAnims(idlestate, movestate, forcestateupdate);
|
refreshCurrentAnims(idlestate, movestate, forcestateupdate);
|
||||||
|
|
||||||
rot *= duration * Ogre::Math::RadiansToDegrees(1.0f);
|
|
||||||
|
|
||||||
if (!mSkipAnim)
|
if (!mSkipAnim)
|
||||||
{
|
{
|
||||||
|
if(mHitState != CharState_KnockDown)
|
||||||
|
{
|
||||||
|
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 //avoid z-rotating for knockdown
|
||||||
|
world->rotateObject(mPtr, rot.x, rot.y, 0.0f, true);
|
||||||
|
|
||||||
world->queueMovement(mPtr, vec);
|
world->queueMovement(mPtr, vec);
|
||||||
}
|
}
|
||||||
|
|
||||||
movement = vec;
|
movement = vec;
|
||||||
}
|
}
|
||||||
else if(cls.getCreatureStats(mPtr).isDead())
|
else if(cls.getCreatureStats(mPtr).isDead())
|
||||||
|
@ -1056,14 +1154,7 @@ void CharacterController::forceStateUpdate()
|
||||||
refreshCurrentAnims(mIdleState, mMovementState, true);
|
refreshCurrentAnims(mIdleState, mMovementState, true);
|
||||||
if(mDeathState != CharState_None)
|
if(mDeathState != CharState_None)
|
||||||
{
|
{
|
||||||
const StateInfo *state = std::find_if(sDeathList, sDeathListEnd, FindCharState(mDeathState));
|
playRandomDeath();
|
||||||
if(state == sDeathListEnd)
|
|
||||||
throw std::runtime_error("Failed to find character state "+Ogre::StringConverter::toString(mDeathState));
|
|
||||||
|
|
||||||
mCurrentDeath = state->groupname;
|
|
||||||
if(!mAnimation->getInfo(mCurrentDeath))
|
|
||||||
mAnimation->play(mCurrentDeath, Priority_Death, MWRender::Animation::Group_All,
|
|
||||||
false, 1.0f, "start", "stop", 0.0f, 0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1072,44 +1163,10 @@ void CharacterController::kill()
|
||||||
if(mDeathState != CharState_None)
|
if(mDeathState != CharState_None)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if(mPtr.getTypeName() == typeid(ESM::NPC).name())
|
playRandomDeath();
|
||||||
{
|
|
||||||
const StateInfo *state = NULL;
|
|
||||||
if(MWBase::Environment::get().getWorld()->isSwimming(mPtr))
|
|
||||||
{
|
|
||||||
mDeathState = CharState_SwimDeath;
|
|
||||||
state = std::find_if(sDeathList, sDeathListEnd, FindCharState(mDeathState));
|
|
||||||
if(state == sDeathListEnd)
|
|
||||||
throw std::runtime_error("Failed to find character state "+Ogre::StringConverter::toString(mDeathState));
|
|
||||||
}
|
|
||||||
|
|
||||||
static const CharacterState deathstates[5] = {
|
|
||||||
CharState_Death1, CharState_Death2, CharState_Death3, CharState_Death4, CharState_Death5
|
|
||||||
};
|
|
||||||
std::vector<CharacterState> states(&deathstates[0], &deathstates[5]);
|
|
||||||
|
|
||||||
while(states.size() > 1 && (!state || !mAnimation->hasAnimation(state->groupname)))
|
|
||||||
{
|
|
||||||
int pos = (int)(rand()/((double)RAND_MAX+1.0)*states.size());
|
|
||||||
mDeathState = states[pos];
|
|
||||||
states.erase(states.begin()+pos);
|
|
||||||
|
|
||||||
state = std::find_if(sDeathList, sDeathListEnd, FindCharState(mDeathState));
|
|
||||||
if(state == sDeathListEnd)
|
|
||||||
throw std::runtime_error("Failed to find character state "+Ogre::StringConverter::toString(mDeathState));
|
|
||||||
}
|
|
||||||
mCurrentDeath = state->groupname;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mDeathState = CharState_Death1;
|
|
||||||
mCurrentDeath = "death1";
|
|
||||||
}
|
|
||||||
|
|
||||||
if(mAnimation)
|
if(mAnimation)
|
||||||
{
|
{
|
||||||
mAnimation->play(mCurrentDeath, Priority_Death, MWRender::Animation::Group_All,
|
|
||||||
false, 1.0f, "start", "stop", 0.0f, 0);
|
|
||||||
mAnimation->disable(mCurrentIdle);
|
mAnimation->disable(mCurrentIdle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,9 @@ enum Priority {
|
||||||
Priority_Default,
|
Priority_Default,
|
||||||
Priority_Jump,
|
Priority_Jump,
|
||||||
Priority_Movement,
|
Priority_Movement,
|
||||||
|
Priority_Hit,
|
||||||
Priority_Weapon,
|
Priority_Weapon,
|
||||||
|
Priority_Knockdown,
|
||||||
Priority_Torch,
|
Priority_Torch,
|
||||||
|
|
||||||
Priority_Death,
|
Priority_Death,
|
||||||
|
@ -87,7 +89,10 @@ enum CharacterState {
|
||||||
CharState_Death3,
|
CharState_Death3,
|
||||||
CharState_Death4,
|
CharState_Death4,
|
||||||
CharState_Death5,
|
CharState_Death5,
|
||||||
CharState_SwimDeath
|
CharState_SwimDeath,
|
||||||
|
|
||||||
|
CharState_Hit,
|
||||||
|
CharState_KnockDown
|
||||||
};
|
};
|
||||||
|
|
||||||
enum WeaponType {
|
enum WeaponType {
|
||||||
|
@ -142,6 +147,9 @@ class CharacterController
|
||||||
CharacterState mDeathState;
|
CharacterState mDeathState;
|
||||||
std::string mCurrentDeath;
|
std::string mCurrentDeath;
|
||||||
|
|
||||||
|
CharacterState mHitState;
|
||||||
|
std::string mCurrentHit;
|
||||||
|
|
||||||
UpperBodyCharacterState mUpperBodyState;
|
UpperBodyCharacterState mUpperBodyState;
|
||||||
|
|
||||||
JumpingState mJumpState;
|
JumpingState mJumpState;
|
||||||
|
@ -172,6 +180,8 @@ class CharacterController
|
||||||
|
|
||||||
void updateVisibility();
|
void updateVisibility();
|
||||||
|
|
||||||
|
void playRandomDeath(float startpoint = 0.0f);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim);
|
CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim);
|
||||||
virtual ~CharacterController();
|
virtual ~CharacterController();
|
||||||
|
|
|
@ -673,7 +673,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())
|
||||||
|
@ -839,7 +852,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);
|
||||||
|
|
||||||
AnimStateMap::iterator stateiter = mStates.begin();
|
AnimStateMap::iterator stateiter = mStates.begin();
|
||||||
while(stateiter != mStates.end())
|
while(stateiter != mStates.end())
|
||||||
{
|
{
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in a new issue