Commit 83872f6b authored by scrawl's avatar scrawl

Knockdown / hit recovery improvements. Use formula and GMSTs from research...

Knockdown / hit recovery improvements. Use formula and GMSTs from research wiki for knockdown determination. Hand-to-hand automatically knocks out when fatigue empty.
parent 3e58eb34
......@@ -242,6 +242,9 @@ namespace MWClass
fJumpAcroMultiplier = gmst.find("fJumpAcroMultiplier");
fJumpRunMultiplier = gmst.find("fJumpRunMultiplier");
fWereWolfRunMult = gmst.find("fWereWolfRunMult");
fKnockDownMult = gmst.find("fKnockDownMult");
iKnockDownOddsMult = gmst.find("iKnockDownOddsMult");
iKnockDownOddsBase = gmst.find("iKnockDownOddsBase");
inited = true;
}
......@@ -651,7 +654,20 @@ namespace MWClass
{
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())
{
......@@ -726,6 +742,15 @@ namespace MWClass
fatigue.setCurrent(fatigue.getCurrent() - damage, true);
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
......@@ -1286,4 +1311,7 @@ namespace MWClass
const ESM::GameSetting *Npc::fJumpAcroMultiplier;
const ESM::GameSetting *Npc::fJumpRunMultiplier;
const ESM::GameSetting *Npc::fWereWolfRunMult;
const ESM::GameSetting *Npc::fKnockDownMult;
const ESM::GameSetting *Npc::iKnockDownOddsMult;
const ESM::GameSetting *Npc::iKnockDownOddsBase;
}
......@@ -33,6 +33,9 @@ namespace MWClass
static const ESM::GameSetting *fJumpAcroMultiplier;
static const ESM::GameSetting *fJumpRunMultiplier;
static const ESM::GameSetting *fWereWolfRunMult;
static const ESM::GameSetting *fKnockDownMult;
static const ESM::GameSetting *iKnockDownOddsMult;
static const ESM::GameSetting *iKnockDownOddsBase;
public:
......
......@@ -157,40 +157,40 @@ public:
void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterState movement, bool force)
{
//hit recoils/knockdown animations handling
if(MWWorld::Class::get(mPtr).isActor())
// hit recoils/knockdown animations handling
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(mHitState == CharState_None)
if(knockdown)
{
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_KnockDown;
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_Hit;
int iHit = rand() % (sHitListSize-1);
//only 3 different hit animations if player is in 1st person
int iHit = rand() % (sHitListSize-3);
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();
if (knockdown)
mPtr.getClass().getCreatureStats(mPtr).setKnockedDown(false);
if (recovery)
mPtr.getClass().getCreatureStats(mPtr).setHitRecovery(false);
mHitState = CharState_None;
}
}
......
......@@ -15,7 +15,7 @@ namespace MWMechanics
mAttacked (false), mHostile (false),
mAttackingOrSpell(false), mAttackType(AT_Chop),
mIsWerewolf(false),
mFallHeight(0), mRecalcDynamicStats(false)
mFallHeight(0), mRecalcDynamicStats(false), mKnockdown(false), mHitRecovery(false)
{
for (int i=0; i<4; ++i)
mAiSettings[i] = 0;
......@@ -402,4 +402,24 @@ namespace MWMechanics
}
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;
}
}
......@@ -34,7 +34,9 @@ namespace MWMechanics
bool mAlarmed;
bool mAttacked;
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;
......@@ -186,6 +188,11 @@ namespace MWMechanics
float getEvasion() const;
void setKnockedDown(bool value);
bool getKnockedDown() const;
void setHitRecovery(bool value);
bool getHitRecovery() const;
void setLastHitObject(const std::string &objectid);
const std::string &getLastHitObject() const;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment