Track death separately in the character controller

This commit is contained in:
Chris Robinson 2013-07-15 23:43:33 -07:00
parent 4ae65c20e6
commit 06e631f213
4 changed files with 66 additions and 36 deletions

View file

@ -168,13 +168,10 @@ namespace MWMechanics
void Actors::addActor (const MWWorld::Ptr& ptr) void Actors::addActor (const MWWorld::Ptr& ptr)
{ {
// erase previous death events since we are currently only tracking them while in an active cell // erase previous death events since we are currently only tracking them while in an active cell
MWWorld::Class::get (ptr).getCreatureStats (ptr).clearHasDied(); MWWorld::Class::get(ptr).getCreatureStats(ptr).clearHasDied();
MWRender::Animation *anim = MWBase::Environment::get().getWorld()->getAnimation(ptr); MWRender::Animation *anim = MWBase::Environment::get().getWorld()->getAnimation(ptr);
if(!MWWorld::Class::get(ptr).getCreatureStats(ptr).isDead()) mActors.insert(std::make_pair(ptr, new CharacterController(ptr, anim)));
mActors.insert(std::make_pair(ptr, new CharacterController(ptr, anim, CharState_Idle)));
else
mActors.insert(std::make_pair(ptr, new CharacterController(ptr, anim, CharState_Death1)));
} }
void Actors::removeActor (const MWWorld::Ptr& ptr) void Actors::removeActor (const MWWorld::Ptr& ptr)
@ -228,8 +225,8 @@ namespace MWMechanics
{ {
if(!MWWorld::Class::get(iter->first).getCreatureStats(iter->first).isDead()) if(!MWWorld::Class::get(iter->first).getCreatureStats(iter->first).isDead())
{ {
if(iter->second->getState() >= CharState_Death1) if(iter->second->isDead())
iter->second->setState(CharState_Idle); iter->second->resurrect();
updateActor(iter->first, totalDuration); updateActor(iter->first, totalDuration);
if(iter->first.getTypeName() == typeid(ESM::NPC).name()) if(iter->first.getTypeName() == typeid(ESM::NPC).name())
@ -256,10 +253,10 @@ namespace MWMechanics
continue; continue;
} }
if(iter->second->getState() >= CharState_Death1) if(iter->second->isDead())
continue; continue;
iter->second->setState(CharState_Death1); iter->second->kill();
++mDeathCount[MWWorld::Class::get(iter->first).getId(iter->first)]; ++mDeathCount[MWWorld::Class::get(iter->first).getId(iter->first)];

View file

@ -221,12 +221,12 @@ void CharacterController::getWeaponGroup(WeaponType weaptype, std::string &group
} }
CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state) CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim)
: mPtr(ptr) : mPtr(ptr)
, mAnimation(anim) , mAnimation(anim)
, mIdleState(CharState_Idle) , mIdleState(CharState_Idle)
, mMovementState(CharState_None) , mMovementState(CharState_None)
, mCharState(state) , mDeathState(CharState_None)
, mWeaponType(WeapType_None) , mWeaponType(WeapType_None)
, mSkipAnim(false) , mSkipAnim(false)
, mSecondsOfRunning(0) , mSecondsOfRunning(0)
@ -241,6 +241,12 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim
/* Accumulate along X/Y only for now, until we can figure out how we should /* Accumulate along X/Y only for now, until we can figure out how we should
* handle knockout and death which moves the character down. */ * handle knockout and death which moves the character down. */
mAnimation->setAccumulation(Ogre::Vector3(1.0f, 1.0f, 0.0f)); mAnimation->setAccumulation(Ogre::Vector3(1.0f, 1.0f, 0.0f));
if(MWWorld::Class::get(mPtr).getCreatureStats(mPtr).isDead())
{
/* FIXME: Get the actual death state used. */
mDeathState = CharState_Death1;
}
} }
else else
{ {
@ -249,13 +255,14 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim
} }
refreshCurrentAnims(mIdleState, mMovementState, true); refreshCurrentAnims(mIdleState, mMovementState, true);
if(mCharState >= CharState_Death1) if(mDeathState != CharState_None)
{ {
const StateInfo *state = std::find_if(sStateList, sStateListEnd, FindCharState(mCharState)); const StateInfo *state = std::find_if(sStateList, sStateListEnd, FindCharState(mDeathState));
if(state == sStateListEnd) if(state == sStateListEnd)
throw std::runtime_error("Failed to find character state "+Ogre::StringConverter::toString(mCharState)); throw std::runtime_error("Failed to find character state "+Ogre::StringConverter::toString(mDeathState));
mAnimation->play(state->groupname, Priority_Death, MWRender::Animation::Group_All, mCurrentDeath = state->groupname;
mAnimation->play(mCurrentDeath, Priority_Death, MWRender::Animation::Group_All,
false, "start", "stop", 1.0f, 0); false, "start", "stop", 1.0f, 0);
} }
} }
@ -608,15 +615,6 @@ void CharacterController::clearAnimQueue()
} }
void CharacterController::setState(CharacterState state)
{
if(mCharState == state)
return;
mCharState = state;
forceStateUpdate();
}
void CharacterController::forceStateUpdate() void CharacterController::forceStateUpdate()
{ {
if(!mAnimation) if(!mAnimation)
@ -624,16 +622,49 @@ void CharacterController::forceStateUpdate()
clearAnimQueue(); clearAnimQueue();
refreshCurrentAnims(mIdleState, mMovementState, true); refreshCurrentAnims(mIdleState, mMovementState, true);
if(mCharState >= CharState_Death1) if(mDeathState != CharState_None)
{ {
const StateInfo *state = std::find_if(sStateList, sStateListEnd, FindCharState(mCharState)); const StateInfo *state = std::find_if(sStateList, sStateListEnd, FindCharState(mDeathState));
if(state == sStateListEnd) if(state == sStateListEnd)
throw std::runtime_error("Failed to find character state "+Ogre::StringConverter::toString(mCharState)); throw std::runtime_error("Failed to find character state "+Ogre::StringConverter::toString(mDeathState));
if(!mAnimation->getInfo(state->groupname)) mCurrentDeath = state->groupname;
mAnimation->play(state->groupname, Priority_Death, MWRender::Animation::Group_All, if(!mAnimation->getInfo(mCurrentDeath))
mAnimation->play(mCurrentDeath, Priority_Death, MWRender::Animation::Group_All,
false, "start", "stop", 0.0f, 0); false, "start", "stop", 0.0f, 0);
} }
} }
void CharacterController::kill()
{
static const CharacterState deathstates[] = {
CharState_Death1, CharState_Death2, CharState_Death3, CharState_Death4, CharState_Death5
};
if(mDeathState != CharState_None)
return;
mDeathState = deathstates[(int)(rand()/((double)RAND_MAX+1.0)*5.0)];
const StateInfo *state = std::find_if(sStateList, sStateListEnd, FindCharState(mDeathState));
if(state == sStateListEnd)
throw std::runtime_error("Failed to find character state "+Ogre::StringConverter::toString(mDeathState));
mCurrentDeath = state->groupname;
if(mAnimation && !mAnimation->getInfo(mCurrentDeath))
mAnimation->play(mCurrentDeath, Priority_Death, MWRender::Animation::Group_All,
false, "start", "stop", 0.0f, 0);
}
void CharacterController::resurrect()
{
if(mDeathState == CharState_None)
return;
if(mAnimation)
mAnimation->disable(mCurrentDeath);
mCurrentDeath.empty();
mDeathState = CharState_None;
}
} }

View file

@ -108,7 +108,9 @@ class CharacterController
CharacterState mMovementState; CharacterState mMovementState;
std::string mCurrentMovement; std::string mCurrentMovement;
CharacterState mCharState; CharacterState mDeathState;
std::string mCurrentDeath;
WeaponType mWeaponType; WeaponType mWeaponType;
bool mSkipAnim; bool mSkipAnim;
@ -126,7 +128,7 @@ class CharacterController
void clearAnimQueue(); void clearAnimQueue();
public: public:
CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state); CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim);
virtual ~CharacterController(); virtual ~CharacterController();
void updatePtr(const MWWorld::Ptr &ptr); void updatePtr(const MWWorld::Ptr &ptr);
@ -137,9 +139,10 @@ public:
void skipAnim(); void skipAnim();
bool isAnimPlaying(const std::string &groupName); bool isAnimPlaying(const std::string &groupName);
void setState(CharacterState state); void kill();
CharacterState getState() const void resurrect();
{ return mCharState; } bool isDead() const
{ return mDeathState != CharState_None; }
void forceStateUpdate(); void forceStateUpdate();
}; };

View file

@ -17,8 +17,7 @@ Objects::Objects()
void Objects::addObject(const MWWorld::Ptr& ptr) void Objects::addObject(const MWWorld::Ptr& ptr)
{ {
MWRender::Animation *anim = MWBase::Environment::get().getWorld()->getAnimation(ptr); MWRender::Animation *anim = MWBase::Environment::get().getWorld()->getAnimation(ptr);
if(anim != NULL) if(anim) mObjects.insert(std::make_pair(ptr, CharacterController(ptr, anim)));
mObjects.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Idle)));
} }
void Objects::removeObject(const MWWorld::Ptr& ptr) void Objects::removeObject(const MWWorld::Ptr& ptr)