1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-03-30 09:06:43 +00:00

Knockdown / hit recovery improvements. Use formula and GMSTs from research wiki for knockdown determination. Hand-to-hand automatically knocks out when fatigue empty.

This commit is contained in:
scrawl 2014-01-13 01:42:19 +01:00
parent 3e58eb34e4
commit 83872f6bf5
5 changed files with 85 additions and 27 deletions

View file

@ -242,6 +242,9 @@ namespace MWClass
fJumpAcroMultiplier = gmst.find("fJumpAcroMultiplier"); fJumpAcroMultiplier = gmst.find("fJumpAcroMultiplier");
fJumpRunMultiplier = gmst.find("fJumpRunMultiplier"); fJumpRunMultiplier = gmst.find("fJumpRunMultiplier");
fWereWolfRunMult = gmst.find("fWereWolfRunMult"); fWereWolfRunMult = gmst.find("fWereWolfRunMult");
fKnockDownMult = gmst.find("fKnockDownMult");
iKnockDownOddsMult = gmst.find("iKnockDownOddsMult");
iKnockDownOddsBase = gmst.find("iKnockDownOddsBase");
inited = true; inited = true;
} }
@ -651,7 +654,20 @@ namespace MWClass
{ {
MWBase::Environment::get().getDialogueManager()->say(ptr, "hit"); MWBase::Environment::get().getDialogueManager()->say(ptr, "hit");
} }
getCreatureStats(ptr).setAttacked(true);//used in CharacterController getCreatureStats(ptr).setAttacked(true);
// Check for knockdown
float agilityTerm = getCreatureStats(ptr).getAttribute(ESM::Attribute::Agility).getModified() * fKnockDownMult->getFloat();
float knockdownTerm = getCreatureStats(ptr).getAttribute(ESM::Attribute::Agility).getModified()
* iKnockDownOddsMult->getInt() * 0.01 + iKnockDownOddsBase->getInt();
roll = std::rand()/ (static_cast<double> (RAND_MAX) + 1) * 100; // [0, 99]
if (ishealth && agilityTerm <= damage && knockdownTerm <= roll)
{
getCreatureStats(ptr).setKnockedDown(true);
}
else
getCreatureStats(ptr).setHitRecovery(true); // Is this supposed to always occur?
if(object.isEmpty()) if(object.isEmpty())
{ {
@ -726,6 +742,15 @@ namespace MWClass
fatigue.setCurrent(fatigue.getCurrent() - damage, true); fatigue.setCurrent(fatigue.getCurrent() - damage, true);
getCreatureStats(ptr).setFatigue(fatigue); getCreatureStats(ptr).setFatigue(fatigue);
} }
if (object.isEmpty())
{
// Hand-to-hand automatically knocks down when running out of fatigue
if (getCreatureStats(ptr).getFatigue().getCurrent() < 0)
{
getCreatureStats(ptr).setKnockedDown(true);
}
}
} }
void Npc::setActorHealth(const MWWorld::Ptr& ptr, float health, const MWWorld::Ptr& attacker) const void Npc::setActorHealth(const MWWorld::Ptr& ptr, float health, const MWWorld::Ptr& attacker) const
@ -1286,4 +1311,7 @@ namespace MWClass
const ESM::GameSetting *Npc::fJumpAcroMultiplier; const ESM::GameSetting *Npc::fJumpAcroMultiplier;
const ESM::GameSetting *Npc::fJumpRunMultiplier; const ESM::GameSetting *Npc::fJumpRunMultiplier;
const ESM::GameSetting *Npc::fWereWolfRunMult; const ESM::GameSetting *Npc::fWereWolfRunMult;
const ESM::GameSetting *Npc::fKnockDownMult;
const ESM::GameSetting *Npc::iKnockDownOddsMult;
const ESM::GameSetting *Npc::iKnockDownOddsBase;
} }

View file

@ -33,6 +33,9 @@ namespace MWClass
static const ESM::GameSetting *fJumpAcroMultiplier; static const ESM::GameSetting *fJumpAcroMultiplier;
static const ESM::GameSetting *fJumpRunMultiplier; static const ESM::GameSetting *fJumpRunMultiplier;
static const ESM::GameSetting *fWereWolfRunMult; static const ESM::GameSetting *fWereWolfRunMult;
static const ESM::GameSetting *fKnockDownMult;
static const ESM::GameSetting *iKnockDownOddsMult;
static const ESM::GameSetting *iKnockDownOddsBase;
public: public:

View file

@ -157,40 +157,40 @@ public:
void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterState movement, bool force) void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterState movement, bool force)
{ {
//hit recoils/knockdown animations handling // hit recoils/knockdown animations handling
if(MWWorld::Class::get(mPtr).isActor()) if(mPtr.getClass().isActor())
{ {
if(MWWorld::Class::get(mPtr).getCreatureStats(mPtr).getAttacked()) bool recovery = mPtr.getClass().getCreatureStats(mPtr).getHitRecovery();
bool knockdown = mPtr.getClass().getCreatureStats(mPtr).getKnockedDown();
if(mHitState == CharState_None)
{ {
MWWorld::Class::get(mPtr).getCreatureStats(mPtr).setAttacked(false); if(knockdown)
if(mHitState == CharState_None)
{ {
if(mJumpState != JumpState_None && !MWBase::Environment::get().getWorld()->isFlying(mPtr) mHitState = CharState_KnockDown;
&& !MWBase::Environment::get().getWorld()->isSwimming(mPtr) ) mCurrentHit = sHitList[sHitListSize-1];
mAnimation->play(mCurrentHit, Priority_Knockdown, MWRender::Animation::Group_All, true, 1, "start", "stop", 0.0f, 0);
}
else if (recovery)
{
mHitState = CharState_Hit;
int iHit = rand() % (sHitListSize-1);
mCurrentHit = sHitList[iHit];
if(mPtr.getRefData().getHandle()=="player" && !mAnimation->hasAnimation(mCurrentHit))
{ {
mHitState = CharState_KnockDown; //only 3 different hit animations if player is in 1st person
mCurrentHit = sHitList[sHitListSize-1]; int iHit = rand() % (sHitListSize-3);
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]; mCurrentHit = sHitList[iHit];
if(mPtr.getRefData().getHandle()=="player" && !mAnimation->hasAnimation(mCurrentHit))
{
//only 3 different hit animations if player is in 1st person
int iHit = rand() % (sHitListSize-3);
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(!mAnimation->isPlaying(mCurrentHit))
{ {
mCurrentHit.erase(); mCurrentHit.erase();
if (knockdown)
mPtr.getClass().getCreatureStats(mPtr).setKnockedDown(false);
if (recovery)
mPtr.getClass().getCreatureStats(mPtr).setHitRecovery(false);
mHitState = CharState_None; mHitState = CharState_None;
} }
} }

View file

@ -15,7 +15,7 @@ namespace MWMechanics
mAttacked (false), mHostile (false), mAttacked (false), mHostile (false),
mAttackingOrSpell(false), mAttackType(AT_Chop), mAttackingOrSpell(false), mAttackType(AT_Chop),
mIsWerewolf(false), mIsWerewolf(false),
mFallHeight(0), mRecalcDynamicStats(false) mFallHeight(0), mRecalcDynamicStats(false), mKnockdown(false), mHitRecovery(false)
{ {
for (int i=0; i<4; ++i) for (int i=0; i<4; ++i)
mAiSettings[i] = 0; mAiSettings[i] = 0;
@ -402,4 +402,24 @@ namespace MWMechanics
} }
return false; return false;
} }
void CreatureStats::setKnockedDown(bool value)
{
mKnockdown = value;
}
bool CreatureStats::getKnockedDown() const
{
return mKnockdown;
}
void CreatureStats::setHitRecovery(bool value)
{
mHitRecovery = value;
}
bool CreatureStats::getHitRecovery() const
{
return mHitRecovery;
}
} }

View file

@ -34,7 +34,9 @@ namespace MWMechanics
bool mAlarmed; bool mAlarmed;
bool mAttacked; bool mAttacked;
bool mHostile; bool mHostile;
bool mAttackingOrSpell;//for the player, this is true if the left mouse button is pressed, false if not. bool mAttackingOrSpell;
bool mKnockdown;
bool mHitRecovery;
float mFallHeight; float mFallHeight;
@ -186,6 +188,11 @@ namespace MWMechanics
float getEvasion() const; float getEvasion() const;
void setKnockedDown(bool value);
bool getKnockedDown() const;
void setHitRecovery(bool value);
bool getHitRecovery() const;
void setLastHitObject(const std::string &objectid); void setLastHitObject(const std::string &objectid);
const std::string &getLastHitObject() const; const std::string &getLastHitObject() const;