From f1ec8db393f5ff7bae77bf0ba16540763c5b56e9 Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Sat, 20 Nov 2021 00:15:18 +0100 Subject: [PATCH] Make Set- and ModStat behave as they should --- CHANGELOG.md | 1 + apps/openmw/mwmechanics/stat.cpp | 15 +++++++- apps/openmw/mwmechanics/stat.hpp | 7 ++-- apps/openmw/mwscript/statsextensions.cpp | 47 ++++++++++-------------- 4 files changed, 38 insertions(+), 32 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2f5b83f158..0cff18a5f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ Bug #1751: Birthsign abilities increase modified attribute values instead of base ones Bug #1930: Followers are still fighting if a target stops combat with a leader + Bug #2036: SetStat and ModStat instructions aren't implemented the same way as in Morrowind Bug #3246: ESSImporter: Most NPCs are dead on save load Bug #3488: AI combat aiming is too slow Bug #3514: Editing a reference's position after loading an esp file makes the reference disappear diff --git a/apps/openmw/mwmechanics/stat.cpp b/apps/openmw/mwmechanics/stat.cpp index c87de2ccbb..ee484f5afd 100644 --- a/apps/openmw/mwmechanics/stat.cpp +++ b/apps/openmw/mwmechanics/stat.cpp @@ -246,14 +246,25 @@ namespace MWMechanics return mModifier; } - void AttributeValue::setBase(float base) + void AttributeValue::setBase(float base, bool clearModifier) { mBase = base; + if(clearModifier) + { + mModifier = 0.f; + mDamage = 0.f; + } } void AttributeValue::setModifier(float mod) { - mModifier = mod; + if(mod < 0) + { + mModifier = 0.f; + mDamage -= mod; + } + else + mModifier = mod; } void AttributeValue::damage(float damage) diff --git a/apps/openmw/mwmechanics/stat.hpp b/apps/openmw/mwmechanics/stat.hpp index fb9dca9221..c80c5b1b70 100644 --- a/apps/openmw/mwmechanics/stat.hpp +++ b/apps/openmw/mwmechanics/stat.hpp @@ -133,13 +133,14 @@ namespace MWMechanics float getBase() const; float getModifier() const; - void setBase(float base); + void setBase(float base, bool clearModifier = false); void setModifier(float mod); // Maximum attribute damage is limited to the modified value. - // Note: I think MW applies damage directly to mModified, since you can also - // "restore" drained attributes. We need to rewrite the magic effect system to support this. + // Note: MW applies damage directly to mModified, however it does track how much + // a damaged attribute that has been fortified beyond its base can be restored. + // Getting rid of mDamage would require calculating its value by ignoring active effects when restoring void damage(float damage); void restore(float amount); diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index ccad186a0d..e57a9570f2 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -40,6 +40,22 @@ namespace return factionId; } + + void modStat(MWMechanics::AttributeValue& stat, float amount) + { + float base = stat.getBase(); + float modifier = stat.getModifier() - stat.getDamage(); + float modified = base + modifier; + if(modified <= 0.f && amount < 0.f) + amount = 0.f; + else if(amount < 0.f && modified + amount < 0.f) + amount = -modified; + else if((modifier <= 0.f || base >= 100.f) && amount > 0.f) + amount = std::clamp(100.f - modified, 0.f, amount); + stat.setBase(std::min(base + amount, 100.f), true); + modifier += base - stat.getBase() + amount; + stat.setModifier(modifier); + } } namespace MWScript @@ -122,7 +138,7 @@ namespace MWScript runtime.pop(); MWMechanics::AttributeValue attribute = ptr.getClass().getCreatureStats(ptr).getAttribute(mIndex); - attribute.setBase (value); + attribute.setBase(value, true); ptr.getClass().getCreatureStats(ptr).setAttribute(mIndex, attribute); } }; @@ -146,19 +162,7 @@ namespace MWScript MWMechanics::AttributeValue attribute = ptr.getClass() .getCreatureStats(ptr) .getAttribute(mIndex); - - if (value == 0) - return; - - if (((attribute.getBase() <= 0) && (value < 0)) - || ((attribute.getBase() >= 100) && (value > 0))) - return; - - if (value < 0) - attribute.setBase(std::max(0.f, attribute.getBase() + value)); - else - attribute.setBase(std::min(100.f, attribute.getBase() + value)); - + modStat(attribute, value); ptr.getClass().getCreatureStats(ptr).setAttribute(mIndex, attribute); } }; @@ -372,7 +376,7 @@ namespace MWScript MWMechanics::NpcStats& stats = ptr.getClass().getNpcStats (ptr); - stats.getSkill (mIndex).setBase (value); + stats.getSkill(mIndex).setBase(value, true); } }; @@ -395,18 +399,7 @@ namespace MWScript MWMechanics::SkillValue &skill = ptr.getClass() .getNpcStats(ptr) .getSkill(mIndex); - - if (value == 0) - return; - - if (((skill.getBase() <= 0.f) && (value < 0.f)) - || ((skill.getBase() >= 100.f) && (value > 0.f))) - return; - - if (value < 0) - skill.setBase(std::max(0.f, skill.getBase() + value)); - else - skill.setBase(std::min(100.f, skill.getBase() + value)); + modStat(skill, value); } };