mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-19 20:53:50 +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:
parent
3e58eb34e4
commit
83872f6bf5
5 changed files with 85 additions and 27 deletions
|
@ -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 if (recovery)
|
||||
{
|
||||
mHitState = CharState_Hit;
|
||||
int iHit = rand() % (sHitListSize-1);
|
||||
mCurrentHit = sHitList[iHit];
|
||||
if(mPtr.getRefData().getHandle()=="player" && !mAnimation->hasAnimation(mCurrentHit))
|
||||
{
|
||||
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);
|
||||
//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;
|
||||
|
||||
|
|
Loading…
Reference in a new issue