1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-02-07 21:40:11 +00:00

Store attributes and skills values as floats (bug #4021)

This commit is contained in:
Andrei Kortunov 2018-12-23 15:18:33 +04:00
parent 2eb9d4ad4e
commit 5468fcb29f
41 changed files with 153 additions and 124 deletions

View File

@ -5,6 +5,7 @@
Bug #2311: Targeted scripts are not properly supported on non-unique RefIDs Bug #2311: Targeted scripts are not properly supported on non-unique RefIDs
Bug #3676: NiParticleColorModifier isn't applied properly Bug #3676: NiParticleColorModifier isn't applied properly
Bug #3714: Savegame fails to load due to conflict between SpellState and MagicEffects Bug #3714: Savegame fails to load due to conflict between SpellState and MagicEffects
Bug #4021: Attributes and skills are not stored as floats
Bug #4623: Corprus implementation is incorrect Bug #4623: Corprus implementation is incorrect
Bug #4774: Guards are ignorant of an invisible player that tries to attack them Bug #4774: Guards are ignorant of an invisible player that tries to attack them
Bug #5108: Savegame bloating due to inefficient fog textures format Bug #5108: Savegame bloating due to inefficient fog textures format

View File

@ -276,7 +276,7 @@ namespace MWClass
const MWWorld::LiveCellRef<ESM::Armor> *ref = ptr.get<ESM::Armor>(); const MWWorld::LiveCellRef<ESM::Armor> *ref = ptr.get<ESM::Armor>();
int armorSkillType = getEquipmentSkill(ptr); int armorSkillType = getEquipmentSkill(ptr);
int armorSkill = actor.getClass().getSkill(actor, armorSkillType); float armorSkill = actor.getClass().getSkill(actor, armorSkillType);
const MWBase::World *world = MWBase::Environment::get().getWorld(); const MWBase::World *world = MWBase::Environment::get().getWorld();
int iBaseArmorSkill = world->getStore().get<ESM::GameSetting>().find("iBaseArmorSkill")->mValue.getInteger(); int iBaseArmorSkill = world->getStore().get<ESM::GameSetting>().find("iBaseArmorSkill")->mValue.getInteger();

View File

@ -605,7 +605,7 @@ namespace MWClass
float Creature::getCapacity (const MWWorld::Ptr& ptr) const float Creature::getCapacity (const MWWorld::Ptr& ptr) const
{ {
const MWMechanics::CreatureStats& stats = getCreatureStats (ptr); const MWMechanics::CreatureStats& stats = getCreatureStats (ptr);
return static_cast<float>(stats.getAttribute(ESM::Attribute::Strength).getModified() * 5); return stats.getAttribute(ESM::Attribute::Strength).getModified() * 5;
} }
int Creature::getServices(const MWWorld::ConstPtr &actor) const int Creature::getServices(const MWWorld::ConstPtr &actor) const
@ -745,7 +745,7 @@ namespace MWClass
throw std::runtime_error(std::string("Unexpected soundgen type: ")+name); throw std::runtime_error(std::string("Unexpected soundgen type: ")+name);
} }
int Creature::getSkill(const MWWorld::Ptr &ptr, int skill) const float Creature::getSkill(const MWWorld::Ptr &ptr, int skill) const
{ {
MWWorld::LiveCellRef<ESM::Creature> *ref = MWWorld::LiveCellRef<ESM::Creature> *ref =
ptr.get<ESM::Creature>(); ptr.get<ESM::Creature>();

View File

@ -108,7 +108,7 @@ namespace MWClass
virtual bool canSwim (const MWWorld::ConstPtr &ptr) const; virtual bool canSwim (const MWWorld::ConstPtr &ptr) const;
virtual bool canWalk (const MWWorld::ConstPtr &ptr) const; virtual bool canWalk (const MWWorld::ConstPtr &ptr) const;
virtual int getSkill(const MWWorld::Ptr &ptr, int skill) const; virtual float getSkill(const MWWorld::Ptr &ptr, int skill) const;
/// Get a blood texture suitable for \a ptr (see Blood Texture 0-2 in Morrowind.ini) /// Get a blood texture suitable for \a ptr (see Blood Texture 0-2 in Morrowind.ini)
virtual int getBloodTexture (const MWWorld::ConstPtr& ptr) const; virtual int getBloodTexture (const MWWorld::ConstPtr& ptr) const;

View File

@ -125,7 +125,7 @@ namespace MWClass
} }
MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayerPtr(); MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayerPtr();
int alchemySkill = player.getClass().getSkill(player, ESM::Skill::Alchemy); float alchemySkill = player.getClass().getSkill(player, ESM::Skill::Alchemy);
static const float fWortChanceValue = static const float fWortChanceValue =
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fWortChanceValue")->mValue.getFloat(); MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fWortChanceValue")->mValue.getFloat();

View File

@ -127,8 +127,8 @@ namespace
} }
// initial health // initial health
int strength = creatureStats.getAttribute(ESM::Attribute::Strength).getBase(); float strength = creatureStats.getAttribute(ESM::Attribute::Strength).getBase();
int endurance = creatureStats.getAttribute(ESM::Attribute::Endurance).getBase(); float endurance = creatureStats.getAttribute(ESM::Attribute::Endurance).getBase();
int multiplier = 3; int multiplier = 3;
@ -1011,7 +1011,7 @@ namespace MWClass
gmst.fJumpEncumbranceMultiplier->mValue.getFloat() * gmst.fJumpEncumbranceMultiplier->mValue.getFloat() *
(1.0f - Npc::getNormalizedEncumbrance(ptr)); (1.0f - Npc::getNormalizedEncumbrance(ptr));
float a = static_cast<float>(getSkill(ptr, ESM::Skill::Acrobatics)); float a = getSkill(ptr, ESM::Skill::Acrobatics);
float b = 0.0f; float b = 0.0f;
if(a > 50.0f) if(a > 50.0f)
{ {
@ -1136,7 +1136,7 @@ namespace MWClass
float fUnarmoredBase1 = store.find("fUnarmoredBase1")->mValue.getFloat(); float fUnarmoredBase1 = store.find("fUnarmoredBase1")->mValue.getFloat();
float fUnarmoredBase2 = store.find("fUnarmoredBase2")->mValue.getFloat(); float fUnarmoredBase2 = store.find("fUnarmoredBase2")->mValue.getFloat();
int unarmoredSkill = getSkill(ptr, ESM::Skill::Unarmored); float unarmoredSkill = getSkill(ptr, ESM::Skill::Unarmored);
float ratings[MWWorld::InventoryStore::Slots]; float ratings[MWWorld::InventoryStore::Slots];
for(int i = 0;i < MWWorld::InventoryStore::Slots;i++) for(int i = 0;i < MWWorld::InventoryStore::Slots;i++)
@ -1283,7 +1283,7 @@ namespace MWClass
return MWWorld::Ptr(cell.insert(ref), &cell); return MWWorld::Ptr(cell.insert(ref), &cell);
} }
int Npc::getSkill(const MWWorld::Ptr& ptr, int skill) const float Npc::getSkill(const MWWorld::Ptr& ptr, int skill) const
{ {
return getNpcStats(ptr).getSkill(skill).getModified(); return getNpcStats(ptr).getSkill(skill).getModified();
} }

View File

@ -129,7 +129,7 @@ namespace MWClass
virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; virtual std::string getModel(const MWWorld::ConstPtr &ptr) const;
virtual int getSkill(const MWWorld::Ptr& ptr, int skill) const; virtual float getSkill(const MWWorld::Ptr& ptr, int skill) const;
/// Get a blood texture suitable for \a ptr (see Blood Texture 0-2 in Morrowind.ini) /// Get a blood texture suitable for \a ptr (see Blood Texture 0-2 in Morrowind.ini)
virtual int getBloodTexture (const MWWorld::ConstPtr& ptr) const; virtual int getBloodTexture (const MWWorld::ConstPtr& ptr) const;

View File

@ -95,9 +95,9 @@ namespace MWGui
MWMechanics::SkillValue& value = player.getClass().getNpcStats(player).getSkill(skill); MWMechanics::SkillValue& value = player.getClass().getNpcStats(player).getSkill(skill);
if (skill == ESM::Skill::Security || skill == ESM::Skill::Sneak) if (skill == ESM::Skill::Security || skill == ESM::Skill::Sneak)
value.setBase(std::min(100, value.getBase()+1)); value.setBase(std::min(100.f, value.getBase()+1));
else else
value.setBase(std::max(0, value.getBase()-1)); value.setBase(std::max(0.f, value.getBase()-1));
} }
const MWWorld::Store<ESM::GameSetting>& gmst = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>(); const MWWorld::Store<ESM::GameSetting>& gmst = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();

View File

@ -157,7 +157,7 @@ namespace MWGui
mAttributeValues[i]->setEnabled(true); mAttributeValues[i]->setEnabled(true);
availableAttributes++; availableAttributes++;
int mult = pcStats.getLevelupAttributeMultiplier (i); float mult = pcStats.getLevelupAttributeMultiplier (i);
mult = std::min(mult, 100-pcStats.getAttribute(i).getBase()); mult = std::min(mult, 100-pcStats.getAttribute(i).getBase());
text->setCaption(mult <= 1 ? "" : "x" + MyGUI::utility::toString(mult)); text->setCaption(mult <= 1 ? "" : "x" + MyGUI::utility::toString(mult));
} }

View File

@ -22,7 +22,7 @@ namespace MWGui
{ {
MWWorld::Ptr player = MWMechanics::getPlayer(); MWWorld::Ptr player = MWMechanics::getPlayer();
mSourceModel = sourceModel; mSourceModel = sourceModel;
int chance = player.getClass().getSkill(player, ESM::Skill::Sneak); float chance = player.getClass().getSkill(player, ESM::Skill::Sneak);
mSourceModel->update(); mSourceModel->update();

View File

@ -159,7 +159,7 @@ namespace MWGui
for (int i=0; ids[i]; ++i) for (int i=0; ids[i]; ++i)
if (ids[i]==id) if (ids[i]==id)
{ {
setText (id, std::to_string(value.getModified())); setText (id, std::to_string(static_cast<int>(value.getModified())));
MyGUI::TextBox* box; MyGUI::TextBox* box;
getWidget(box, id); getWidget(box, id);

View File

@ -74,11 +74,11 @@ namespace MWGui
mPlayerGold->setCaptionWithReplacing("#{sGold}: " + MyGUI::utility::toString(playerGold)); mPlayerGold->setCaptionWithReplacing("#{sGold}: " + MyGUI::utility::toString(playerGold));
// NPC can train you in his best 3 skills // NPC can train you in his best 3 skills
std::vector< std::pair<int, int> > skills; std::vector< std::pair<int, float> > skills;
for (int i=0; i<ESM::Skill::Length; ++i) for (int i=0; i<ESM::Skill::Length; ++i)
{ {
int value = actor.getClass().getSkill(actor, i); float value = actor.getClass().getSkill(actor, i);
skills.push_back(std::make_pair(i, value)); skills.push_back(std::make_pair(i, value));
} }

View File

@ -132,7 +132,7 @@ void getRestorationPerHourOfSleep (const MWWorld::Ptr& ptr, float& health, float
MWMechanics::CreatureStats& stats = ptr.getClass().getCreatureStats (ptr); MWMechanics::CreatureStats& stats = ptr.getClass().getCreatureStats (ptr);
const MWWorld::Store<ESM::GameSetting>& settings = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>(); const MWWorld::Store<ESM::GameSetting>& settings = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
int endurance = stats.getAttribute (ESM::Attribute::Endurance).getModified (); float endurance = stats.getAttribute (ESM::Attribute::Endurance).getModified ();
health = 0.1f * endurance; health = 0.1f * endurance;
float fRestMagicMult = settings.find("fRestMagicMult")->mValue.getFloat (); float fRestMagicMult = settings.find("fRestMagicMult")->mValue.getFloat ();
@ -765,7 +765,7 @@ namespace MWMechanics
{ {
CreatureStats& creatureStats = ptr.getClass().getCreatureStats (ptr); CreatureStats& creatureStats = ptr.getClass().getCreatureStats (ptr);
int intelligence = creatureStats.getAttribute(ESM::Attribute::Intelligence).getModified(); float intelligence = creatureStats.getAttribute(ESM::Attribute::Intelligence).getModified();
float base = 1.f; float base = 1.f;
if (ptr == getPlayer()) if (ptr == getPlayer())
@ -844,7 +844,7 @@ namespace MWMechanics
float fFatigueReturnMult = settings.find("fFatigueReturnMult")->mValue.getFloat (); float fFatigueReturnMult = settings.find("fFatigueReturnMult")->mValue.getFloat ();
float fEndFatigueMult = settings.find("fEndFatigueMult")->mValue.getFloat (); float fEndFatigueMult = settings.find("fEndFatigueMult")->mValue.getFloat ();
int endurance = stats.getAttribute (ESM::Attribute::Endurance).getModified (); float endurance = stats.getAttribute (ESM::Attribute::Endurance).getModified ();
float normalizedEncumbrance = ptr.getClass().getNormalizedEncumbrance(ptr); float normalizedEncumbrance = ptr.getClass().getNormalizedEncumbrance(ptr);
if (normalizedEncumbrance > 1) if (normalizedEncumbrance > 1)
@ -871,7 +871,7 @@ namespace MWMechanics
return; return;
// Restore fatigue // Restore fatigue
int endurance = stats.getAttribute(ESM::Attribute::Endurance).getModified(); float endurance = stats.getAttribute(ESM::Attribute::Endurance).getModified();
const MWWorld::Store<ESM::GameSetting>& settings = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>(); const MWWorld::Store<ESM::GameSetting>& settings = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
static const float fFatigueReturnBase = settings.find("fFatigueReturnBase")->mValue.getFloat (); static const float fFatigueReturnBase = settings.find("fFatigueReturnBase")->mValue.getFloat ();
static const float fFatigueReturnMult = settings.find("fFatigueReturnMult")->mValue.getFloat (); static const float fFatigueReturnMult = settings.find("fFatigueReturnMult")->mValue.getFloat ();

View File

@ -468,7 +468,7 @@ MWMechanics::Alchemy::TEffectsIterator MWMechanics::Alchemy::endEffects() const
bool MWMechanics::Alchemy::knownEffect(unsigned int potionEffectIndex, const MWWorld::Ptr &npc) bool MWMechanics::Alchemy::knownEffect(unsigned int potionEffectIndex, const MWWorld::Ptr &npc)
{ {
int alchemySkill = npc.getClass().getSkill (npc, ESM::Skill::Alchemy); float alchemySkill = npc.getClass().getSkill (npc, ESM::Skill::Alchemy);
static const float fWortChanceValue = static const float fWortChanceValue =
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fWortChanceValue")->mValue.getFloat(); MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fWortChanceValue")->mValue.getFloat();
return (potionEffectIndex <= 1 && alchemySkill >= fWortChanceValue) return (potionEffectIndex <= 1 && alchemySkill >= fWortChanceValue)

View File

@ -2128,7 +2128,7 @@ void CharacterController::update(float duration, bool animationOnly)
cls.onHit(mPtr, realHealthLost, true, MWWorld::Ptr(), MWWorld::Ptr(), osg::Vec3f(), true); cls.onHit(mPtr, realHealthLost, true, MWWorld::Ptr(), MWWorld::Ptr(), osg::Vec3f(), true);
} }
const int acrobaticsSkill = cls.getSkill(mPtr, ESM::Skill::Acrobatics); const float acrobaticsSkill = cls.getSkill(mPtr, ESM::Skill::Acrobatics);
if (healthLost > (acrobaticsSkill * fatigueTerm)) if (healthLost > (acrobaticsSkill * fatigueTerm))
{ {
if (!godmode) if (!godmode)

View File

@ -101,7 +101,7 @@ namespace MWMechanics
blockerTerm *= gmst.find("fBlockStillBonus")->mValue.getFloat(); blockerTerm *= gmst.find("fBlockStillBonus")->mValue.getFloat();
blockerTerm *= blockerStats.getFatigueTerm(); blockerTerm *= blockerStats.getFatigueTerm();
int attackerSkill = 0; float attackerSkill = 0;
if (weapon.isEmpty()) if (weapon.isEmpty())
attackerSkill = attacker.getClass().getSkill(attacker, ESM::Skill::HandToHand); attackerSkill = attacker.getClass().getSkill(attacker, ESM::Skill::HandToHand);
else else

View File

@ -126,7 +126,7 @@ namespace MWMechanics
return mMagicEffects; return mMagicEffects;
} }
void CreatureStats::setAttribute(int index, int base) void CreatureStats::setAttribute(int index, float base)
{ {
AttributeValue current = getAttribute(index); AttributeValue current = getAttribute(index);
current.setBase(base); current.setBase(base);
@ -152,10 +152,10 @@ namespace MWMechanics
index == ESM::Attribute::Agility || index == ESM::Attribute::Agility ||
index == ESM::Attribute::Endurance) index == ESM::Attribute::Endurance)
{ {
int strength = getAttribute(ESM::Attribute::Strength).getModified(); float strength = getAttribute(ESM::Attribute::Strength).getModified();
int willpower = getAttribute(ESM::Attribute::Willpower).getModified(); float willpower = getAttribute(ESM::Attribute::Willpower).getModified();
int agility = getAttribute(ESM::Attribute::Agility).getModified(); float agility = getAttribute(ESM::Attribute::Agility).getModified();
int endurance = getAttribute(ESM::Attribute::Endurance).getModified(); float endurance = getAttribute(ESM::Attribute::Endurance).getModified();
DynamicStat<float> fatigue = getFatigue(); DynamicStat<float> fatigue = getFatigue();
float diff = (strength+willpower+agility+endurance) - fatigue.getBase(); float diff = (strength+willpower+agility+endurance) - fatigue.getBase();
float currentToBaseRatio = fatigue.getBase() > 0 ? (fatigue.getCurrent() / fatigue.getBase()) : 0; float currentToBaseRatio = fatigue.getBase() > 0 ? (fatigue.getCurrent() / fatigue.getBase()) : 0;

View File

@ -138,7 +138,7 @@ namespace MWMechanics
void setAttribute(int index, const AttributeValue &value); void setAttribute(int index, const AttributeValue &value);
// Shortcut to set only the base // Shortcut to set only the base
void setAttribute(int index, int base); void setAttribute(int index, float base);
void setHealth(const DynamicStat<float> &value); void setHealth(const DynamicStat<float> &value);

View File

@ -688,10 +688,10 @@ namespace MWMechanics
// I suppose the temporary disposition change (second param to getDerivedDisposition()) _has_ to be considered here, // I suppose the temporary disposition change (second param to getDerivedDisposition()) _has_ to be considered here,
// otherwise one would get different prices when exiting and re-entering the dialogue window... // otherwise one would get different prices when exiting and re-entering the dialogue window...
int clampedDisposition = getDerivedDisposition(ptr); int clampedDisposition = getDerivedDisposition(ptr);
float a = static_cast<float>(std::min(playerPtr.getClass().getSkill(playerPtr, ESM::Skill::Mercantile), 100)); float a = std::min(playerPtr.getClass().getSkill(playerPtr, ESM::Skill::Mercantile), 100.f);
float b = std::min(0.1f * playerStats.getAttribute(ESM::Attribute::Luck).getModified(), 10.f); float b = std::min(0.1f * playerStats.getAttribute(ESM::Attribute::Luck).getModified(), 10.f);
float c = std::min(0.2f * playerStats.getAttribute(ESM::Attribute::Personality).getModified(), 10.f); float c = std::min(0.2f * playerStats.getAttribute(ESM::Attribute::Personality).getModified(), 10.f);
float d = static_cast<float>(std::min(ptr.getClass().getSkill(ptr, ESM::Skill::Mercantile), 100)); float d = std::min(ptr.getClass().getSkill(ptr, ESM::Skill::Mercantile), 100.f);
float e = std::min(0.1f * sellerStats.getAttribute(ESM::Attribute::Luck).getModified(), 10.f); float e = std::min(0.1f * sellerStats.getAttribute(ESM::Attribute::Luck).getModified(), 10.f);
float f = std::min(0.2f * sellerStats.getAttribute(ESM::Attribute::Personality).getModified(), 10.f); float f = std::min(0.2f * sellerStats.getAttribute(ESM::Attribute::Personality).getModified(), 10.f);
float pcTerm = (clampedDisposition - 50 + a + b + c) * playerStats.getFatigueTerm(); float pcTerm = (clampedDisposition - 50 + a + b + c) * playerStats.getFatigueTerm();
@ -1621,8 +1621,8 @@ namespace MWMechanics
static float fSneakSkillMult = store.find("fSneakSkillMult")->mValue.getFloat(); static float fSneakSkillMult = store.find("fSneakSkillMult")->mValue.getFloat();
static float fSneakBootMult = store.find("fSneakBootMult")->mValue.getFloat(); static float fSneakBootMult = store.find("fSneakBootMult")->mValue.getFloat();
float sneak = static_cast<float>(ptr.getClass().getSkill(ptr, ESM::Skill::Sneak)); float sneak = static_cast<float>(ptr.getClass().getSkill(ptr, ESM::Skill::Sneak));
int agility = stats.getAttribute(ESM::Attribute::Agility).getModified(); float agility = stats.getAttribute(ESM::Attribute::Agility).getModified();
int luck = stats.getAttribute(ESM::Attribute::Luck).getModified(); float luck = stats.getAttribute(ESM::Attribute::Luck).getModified();
float bootWeight = 0; float bootWeight = 0;
if (ptr.getClass().isNpc() && MWBase::Environment::get().getWorld()->isOnGround(ptr)) if (ptr.getClass().isNpc() && MWBase::Environment::get().getWorld()->isOnGround(ptr))
{ {
@ -1645,10 +1645,10 @@ namespace MWMechanics
float x = sneakTerm * distTerm * stats.getFatigueTerm() + chameleon + invisibility; float x = sneakTerm * distTerm * stats.getFatigueTerm() + chameleon + invisibility;
CreatureStats& observerStats = observer.getClass().getCreatureStats(observer); CreatureStats& observerStats = observer.getClass().getCreatureStats(observer);
int obsAgility = observerStats.getAttribute(ESM::Attribute::Agility).getModified(); float obsAgility = observerStats.getAttribute(ESM::Attribute::Agility).getModified();
int obsLuck = observerStats.getAttribute(ESM::Attribute::Luck).getModified(); float obsLuck = observerStats.getAttribute(ESM::Attribute::Luck).getModified();
float obsBlind = observerStats.getMagicEffects().get(ESM::MagicEffect::Blind).getMagnitude(); float obsBlind = observerStats.getMagicEffects().get(ESM::MagicEffect::Blind).getMagnitude();
int obsSneak = observer.getClass().getSkill(observer, ESM::Skill::Sneak); float obsSneak = observer.getClass().getSkill(observer, ESM::Skill::Sneak);
float obsTerm = obsSneak + 0.2f * obsAgility + 0.1f * obsLuck - obsBlind; float obsTerm = obsSneak + 0.2f * obsAgility + 0.1f * obsLuck - obsBlind;

View File

@ -226,9 +226,9 @@ void MWMechanics::NpcStats::useSkill (int skillIndex, const ESM::Class& class_,
void MWMechanics::NpcStats::increaseSkill(int skillIndex, const ESM::Class &class_, bool preserveProgress, bool readBook) void MWMechanics::NpcStats::increaseSkill(int skillIndex, const ESM::Class &class_, bool preserveProgress, bool readBook)
{ {
int base = getSkill (skillIndex).getBase(); float base = getSkill (skillIndex).getBase();
if (base >= 100) if (base >= 100.f)
return; return;
base += 1; base += 1;
@ -299,7 +299,7 @@ void MWMechanics::NpcStats::levelUp()
for (int i=0; i<ESM::Attribute::Length; ++i) for (int i=0; i<ESM::Attribute::Length; ++i)
mSkillIncreases[i] = 0; mSkillIncreases[i] = 0;
const int endurance = getAttribute(ESM::Attribute::Endurance).getBase(); const float endurance = getAttribute(ESM::Attribute::Endurance).getBase();
// "When you gain a level, in addition to increasing three primary attributes, your Health // "When you gain a level, in addition to increasing three primary attributes, your Health
// will automatically increase by 10% of your Endurance attribute. If you increased Endurance this level, // will automatically increase by 10% of your Endurance attribute. If you increased Endurance this level,
@ -316,8 +316,8 @@ void MWMechanics::NpcStats::levelUp()
void MWMechanics::NpcStats::updateHealth() void MWMechanics::NpcStats::updateHealth()
{ {
const int endurance = getAttribute(ESM::Attribute::Endurance).getBase(); const float endurance = getAttribute(ESM::Attribute::Endurance).getBase();
const int strength = getAttribute(ESM::Attribute::Strength).getBase(); const float strength = getAttribute(ESM::Attribute::Strength).getBase();
setHealth(floor(0.5f * (strength + endurance))); setHealth(floor(0.5f * (strength + endurance)));
} }

View File

@ -22,8 +22,8 @@ namespace MWMechanics
float Pickpocket::getChanceModifier(const MWWorld::Ptr &ptr, float add) float Pickpocket::getChanceModifier(const MWWorld::Ptr &ptr, float add)
{ {
NpcStats& stats = ptr.getClass().getNpcStats(ptr); NpcStats& stats = ptr.getClass().getNpcStats(ptr);
float agility = static_cast<float>(stats.getAttribute(ESM::Attribute::Agility).getModified()); float agility = stats.getAttribute(ESM::Attribute::Agility).getModified();
float luck = static_cast<float>(stats.getAttribute(ESM::Attribute::Luck).getModified()); float luck = stats.getAttribute(ESM::Attribute::Luck).getModified();
float sneak = static_cast<float>(ptr.getClass().getSkill(ptr, ESM::Skill::Sneak)); float sneak = static_cast<float>(ptr.getClass().getSkill(ptr, ESM::Skill::Sneak));
return (add + 0.2f * agility + 0.1f * luck + sneak) * stats.getFatigueTerm(); return (add + 0.2f * agility + 0.1f * luck + sneak) * stats.getFatigueTerm();
} }

View File

@ -32,9 +32,9 @@ void Repair::repair(const MWWorld::Ptr &itemToRepair)
MWMechanics::CreatureStats& stats = player.getClass().getCreatureStats(player); MWMechanics::CreatureStats& stats = player.getClass().getCreatureStats(player);
float fatigueTerm = stats.getFatigueTerm(); float fatigueTerm = stats.getFatigueTerm();
int pcStrength = stats.getAttribute(ESM::Attribute::Strength).getModified(); float pcStrength = stats.getAttribute(ESM::Attribute::Strength).getModified();
int pcLuck = stats.getAttribute(ESM::Attribute::Luck).getModified(); float pcLuck = stats.getAttribute(ESM::Attribute::Luck).getModified();
int armorerSkill = player.getClass().getSkill(player, ESM::Skill::Armorer); float armorerSkill = player.getClass().getSkill(player, ESM::Skill::Armorer);
float fRepairAmountMult = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>() float fRepairAmountMult = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>()
.find("fRepairAmountMult")->mValue.getFloat(); .find("fRepairAmountMult")->mValue.getFloat();

View File

@ -19,8 +19,8 @@ namespace MWMechanics
: mActor(actor) : mActor(actor)
{ {
CreatureStats& creatureStats = actor.getClass().getCreatureStats(actor); CreatureStats& creatureStats = actor.getClass().getCreatureStats(actor);
mAgility = static_cast<float>(creatureStats.getAttribute(ESM::Attribute::Agility).getModified()); mAgility = creatureStats.getAttribute(ESM::Attribute::Agility).getModified();
mLuck = static_cast<float>(creatureStats.getAttribute(ESM::Attribute::Luck).getModified()); mLuck = creatureStats.getAttribute(ESM::Attribute::Luck).getModified();
mSecuritySkill = static_cast<float>(actor.getClass().getSkill(actor, ESM::Skill::Security)); mSecuritySkill = static_cast<float>(actor.getClass().getSkill(actor, ESM::Skill::Security));
mFatigueTerm = creatureStats.getFatigueTerm(); mFatigueTerm = creatureStats.getFatigueTerm();
} }

View File

@ -40,8 +40,8 @@ namespace MWMechanics
float resistance = getEffectResistanceAttribute(effectId, magicEffects); float resistance = getEffectResistanceAttribute(effectId, magicEffects);
int willpower = stats.getAttribute(ESM::Attribute::Willpower).getModified(); float willpower = stats.getAttribute(ESM::Attribute::Willpower).getModified();
float luck = static_cast<float>(stats.getAttribute(ESM::Attribute::Luck).getModified()); float luck = stats.getAttribute(ESM::Attribute::Luck).getModified();
float x = (willpower + 0.1f * luck) * stats.getFatigueTerm(); float x = (willpower + 0.1f * luck) * stats.getFatigueTerm();
// This makes spells that are easy to cast harder to resist and vice versa // This makes spells that are easy to cast harder to resist and vice versa

View File

@ -94,8 +94,8 @@ namespace MWMechanics
CreatureStats& stats = actor.getClass().getCreatureStats(actor); CreatureStats& stats = actor.getClass().getCreatureStats(actor);
int actorWillpower = stats.getAttribute(ESM::Attribute::Willpower).getModified(); float actorWillpower = stats.getAttribute(ESM::Attribute::Willpower).getModified();
int actorLuck = stats.getAttribute(ESM::Attribute::Luck).getModified(); float actorLuck = stats.getAttribute(ESM::Attribute::Luck).getModified();
float castChance = (lowestSkill - spell->mData.mCost + 0.2f * actorWillpower + 0.1f * actorLuck); float castChance = (lowestSkill - spell->mData.mCost + 0.2f * actorWillpower + 0.1f * actorLuck);

View File

@ -227,29 +227,29 @@ namespace MWMechanics
} }
AttributeValue::AttributeValue() : AttributeValue::AttributeValue() :
mBase(0), mModifier(0), mDamage(0) mBase(0.f), mModifier(0.f), mDamage(0.f)
{ {
} }
int AttributeValue::getModified() const float AttributeValue::getModified() const
{ {
return std::max(0, mBase - (int) mDamage + mModifier); return std::max(0.f, mBase - mDamage + mModifier);
} }
int AttributeValue::getBase() const float AttributeValue::getBase() const
{ {
return mBase; return mBase;
} }
int AttributeValue::getModifier() const float AttributeValue::getModifier() const
{ {
return mModifier; return mModifier;
} }
void AttributeValue::setBase(int base) void AttributeValue::setBase(float base)
{ {
mBase = base; mBase = base;
} }
void AttributeValue::setModifier(int mod) void AttributeValue::setModifier(float mod)
{ {
mModifier = mod; mModifier = mod;
} }
@ -275,14 +275,14 @@ namespace MWMechanics
return mDamage; return mDamage;
} }
void AttributeValue::writeState (ESM::StatState<int>& state) const void AttributeValue::writeState (ESM::StatState<float>& state) const
{ {
state.mBase = mBase; state.mBase = mBase;
state.mMod = mModifier; state.mMod = mModifier;
state.mDamage = mDamage; state.mDamage = mDamage;
} }
void AttributeValue::readState (const ESM::StatState<int>& state) void AttributeValue::readState (const ESM::StatState<float>& state)
{ {
mBase = state.mBase; mBase = state.mBase;
mModifier = state.mMod; mModifier = state.mMod;
@ -303,13 +303,13 @@ namespace MWMechanics
mProgress = progress; mProgress = progress;
} }
void SkillValue::writeState (ESM::StatState<int>& state) const void SkillValue::writeState (ESM::StatState<float>& state) const
{ {
AttributeValue::writeState (state); AttributeValue::writeState (state);
state.mProgress = mProgress; state.mProgress = mProgress;
} }
void SkillValue::readState (const ESM::StatState<int>& state) void SkillValue::readState (const ESM::StatState<float>& state)
{ {
AttributeValue::readState (state); AttributeValue::readState (state);
mProgress = state.mProgress; mProgress = state.mProgress;

View File

@ -122,20 +122,20 @@ namespace MWMechanics
class AttributeValue class AttributeValue
{ {
int mBase; float mBase;
int mModifier; float mModifier;
float mDamage; // needs to be float to allow continuous damage float mDamage; // needs to be float to allow continuous damage
public: public:
AttributeValue(); AttributeValue();
int getModified() const; float getModified() const;
int getBase() const; float getBase() const;
int getModifier() const; float getModifier() const;
void setBase(int base); void setBase(float base);
void setModifier(int mod); void setModifier(float mod);
// Maximum attribute damage is limited to the modified value. // Maximum attribute damage is limited to the modified value.
// Note: I think MW applies damage directly to mModified, since you can also // Note: I think MW applies damage directly to mModified, since you can also
@ -145,8 +145,8 @@ namespace MWMechanics
float getDamage() const; float getDamage() const;
void writeState (ESM::StatState<int>& state) const; void writeState (ESM::StatState<float>& state) const;
void readState (const ESM::StatState<int>& state); void readState (const ESM::StatState<float>& state);
}; };
class SkillValue : public AttributeValue class SkillValue : public AttributeValue
@ -157,8 +157,8 @@ namespace MWMechanics
float getProgress() const; float getProgress() const;
void setProgress(float progress); void setProgress(float progress);
void writeState (ESM::StatState<int>& state) const; void writeState (ESM::StatState<float>& state) const;
void readState (const ESM::StatState<int>& state); void readState (const ESM::StatState<float>& state);
}; };
inline bool operator== (const AttributeValue& left, const AttributeValue& right) inline bool operator== (const AttributeValue& left, const AttributeValue& right)

View File

@ -95,7 +95,7 @@ namespace MWScript
{ {
MWWorld::Ptr ptr = R()(runtime); MWWorld::Ptr ptr = R()(runtime);
Interpreter::Type_Integer value = Interpreter::Type_Float value =
ptr.getClass() ptr.getClass()
.getCreatureStats (ptr) .getCreatureStats (ptr)
.getAttribute(mIndex) .getAttribute(mIndex)
@ -118,7 +118,7 @@ namespace MWScript
{ {
MWWorld::Ptr ptr = R()(runtime); MWWorld::Ptr ptr = R()(runtime);
Interpreter::Type_Integer value = runtime[0].mInteger; Interpreter::Type_Float value = runtime[0].mFloat;
runtime.pop(); runtime.pop();
MWMechanics::AttributeValue attribute = ptr.getClass().getCreatureStats(ptr).getAttribute(mIndex); MWMechanics::AttributeValue attribute = ptr.getClass().getCreatureStats(ptr).getAttribute(mIndex);
@ -140,7 +140,7 @@ namespace MWScript
{ {
MWWorld::Ptr ptr = R()(runtime); MWWorld::Ptr ptr = R()(runtime);
Interpreter::Type_Integer value = runtime[0].mInteger; Interpreter::Type_Float value = runtime[0].mFloat;
runtime.pop(); runtime.pop();
MWMechanics::AttributeValue attribute = ptr.getClass() MWMechanics::AttributeValue attribute = ptr.getClass()
@ -155,9 +155,9 @@ namespace MWScript
return; return;
if (value < 0) if (value < 0)
attribute.setBase(std::max(0, attribute.getBase() + value)); attribute.setBase(std::max(0.f, attribute.getBase() + value));
else else
attribute.setBase(std::min(100, attribute.getBase() + value)); attribute.setBase(std::min(100.f, attribute.getBase() + value));
ptr.getClass().getCreatureStats(ptr).setAttribute(mIndex, attribute); ptr.getClass().getCreatureStats(ptr).setAttribute(mIndex, attribute);
} }
@ -345,7 +345,7 @@ namespace MWScript
{ {
MWWorld::Ptr ptr = R()(runtime); MWWorld::Ptr ptr = R()(runtime);
Interpreter::Type_Integer value = ptr.getClass().getSkill(ptr, mIndex); Interpreter::Type_Float value = ptr.getClass().getSkill(ptr, mIndex);
runtime.push (value); runtime.push (value);
} }
@ -364,7 +364,7 @@ namespace MWScript
{ {
MWWorld::Ptr ptr = R()(runtime); MWWorld::Ptr ptr = R()(runtime);
Interpreter::Type_Integer value = runtime[0].mInteger; Interpreter::Type_Float value = runtime[0].mFloat;
runtime.pop(); runtime.pop();
MWMechanics::NpcStats& stats = ptr.getClass().getNpcStats (ptr); MWMechanics::NpcStats& stats = ptr.getClass().getNpcStats (ptr);
@ -386,7 +386,7 @@ namespace MWScript
{ {
MWWorld::Ptr ptr = R()(runtime); MWWorld::Ptr ptr = R()(runtime);
Interpreter::Type_Integer value = runtime[0].mInteger; Interpreter::Type_Float value = runtime[0].mFloat;
runtime.pop(); runtime.pop();
MWMechanics::SkillValue &skill = ptr.getClass() MWMechanics::SkillValue &skill = ptr.getClass()
@ -396,14 +396,14 @@ namespace MWScript
if (value == 0) if (value == 0)
return; return;
if (((skill.getBase() <= 0) && (value < 0)) if (((skill.getBase() <= 0.f) && (value < 0.f))
|| ((skill.getBase() >= 100) && (value > 0))) || ((skill.getBase() >= 100.f) && (value > 0.f)))
return; return;
if (value < 0) if (value < 0)
skill.setBase(std::max(0, skill.getBase() + value)); skill.setBase(std::max(0.f, skill.getBase() + value));
else else
skill.setBase(std::min(100, skill.getBase() + value)); skill.setBase(std::min(100.f, skill.getBase() + value));
} }
}; };

View File

@ -421,7 +421,7 @@ namespace MWWorld
return canSwim(ptr) || canWalk(ptr) || canFly(ptr); return canSwim(ptr) || canWalk(ptr) || canFly(ptr);
} }
int Class::getSkill(const MWWorld::Ptr& ptr, int skill) const float Class::getSkill(const MWWorld::Ptr& ptr, int skill) const
{ {
throw std::runtime_error("class does not support skills"); throw std::runtime_error("class does not support skills");
} }

View File

@ -321,7 +321,7 @@ namespace MWWorld
bool isPureLandCreature(const MWWorld::Ptr& ptr) const; bool isPureLandCreature(const MWWorld::Ptr& ptr) const;
bool isMobile(const MWWorld::Ptr& ptr) const; bool isMobile(const MWWorld::Ptr& ptr) const;
virtual int getSkill(const MWWorld::Ptr& ptr, int skill) const; virtual float getSkill(const MWWorld::Ptr& ptr, int skill) const;
virtual void readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) virtual void readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state)
const; const;

View File

@ -284,12 +284,12 @@ void MWWorld::InventoryStore::autoEquipWeapon (const MWWorld::Ptr& actor, TSlots
// rate weapon // rate weapon
for (int i = 0; i < static_cast<int>(weaponSkillsLength); ++i) for (int i = 0; i < static_cast<int>(weaponSkillsLength); ++i)
{ {
int max = 0; float max = 0;
int maxWeaponSkill = -1; int maxWeaponSkill = -1;
for (int j = 0; j < static_cast<int>(weaponSkillsLength); ++j) for (int j = 0; j < static_cast<int>(weaponSkillsLength); ++j)
{ {
int skillValue = actor.getClass().getSkill(actor, static_cast<int>(weaponSkills[j])); float skillValue = actor.getClass().getSkill(actor, static_cast<int>(weaponSkills[j]));
if (skillValue > max && !weaponSkillVisited[j]) if (skillValue > max && !weaponSkillVisited[j])
{ {
max = skillValue; max = skillValue;
@ -399,7 +399,7 @@ void MWWorld::InventoryStore::autoEquipArmor (const MWWorld::Ptr& actor, TSlots&
static float fUnarmoredBase1 = store.find("fUnarmoredBase1")->mValue.getFloat(); static float fUnarmoredBase1 = store.find("fUnarmoredBase1")->mValue.getFloat();
static float fUnarmoredBase2 = store.find("fUnarmoredBase2")->mValue.getFloat(); static float fUnarmoredBase2 = store.find("fUnarmoredBase2")->mValue.getFloat();
int unarmoredSkill = actor.getClass().getSkill(actor, ESM::Skill::Unarmored); float unarmoredSkill = actor.getClass().getSkill(actor, ESM::Skill::Unarmored);
float unarmoredRating = (fUnarmoredBase1 * unarmoredSkill) * (fUnarmoredBase2 * unarmoredSkill); float unarmoredRating = (fUnarmoredBase1 * unarmoredSkill) * (fUnarmoredBase2 * unarmoredSkill);
for (ContainerStoreIterator iter (begin(ContainerStore::Type_Clothing | ContainerStore::Type_Armor)); iter!=end(); ++iter) for (ContainerStoreIterator iter (begin(ContainerStore::Type_Clothing | ContainerStore::Type_Armor)); iter!=end(); ++iter)

View File

@ -423,13 +423,13 @@ namespace Compiler
for (int i=0; i<numberOfAttributes; ++i) for (int i=0; i<numberOfAttributes; ++i)
{ {
extensions.registerFunction (get + attributes[i], 'l', "", extensions.registerFunction (get + attributes[i], 'f', "",
opcodeGetAttribute+i, opcodeGetAttributeExplicit+i); opcodeGetAttribute+i, opcodeGetAttributeExplicit+i);
extensions.registerInstruction (set + attributes[i], "l", extensions.registerInstruction (set + attributes[i], "f",
opcodeSetAttribute+i, opcodeSetAttributeExplicit+i); opcodeSetAttribute+i, opcodeSetAttributeExplicit+i);
extensions.registerInstruction (mod + attributes[i], "l", extensions.registerInstruction (mod + attributes[i], "f",
opcodeModAttribute+i, opcodeModAttributeExplicit+i); opcodeModAttribute+i, opcodeModAttributeExplicit+i);
} }
@ -453,13 +453,13 @@ namespace Compiler
for (int i=0; i<numberOfSkills; ++i) for (int i=0; i<numberOfSkills; ++i)
{ {
extensions.registerFunction (get + skills[i], 'l', "", extensions.registerFunction (get + skills[i], 'f', "",
opcodeGetSkill+i, opcodeGetSkillExplicit+i); opcodeGetSkill+i, opcodeGetSkillExplicit+i);
extensions.registerInstruction (set + skills[i], "l", extensions.registerInstruction (set + skills[i], "f",
opcodeSetSkill+i, opcodeSetSkillExplicit+i); opcodeSetSkill+i, opcodeSetSkillExplicit+i);
extensions.registerInstruction (mod + skills[i], "l", extensions.registerInstruction (mod + skills[i], "f",
opcodeModSkill+i, opcodeModSkillExplicit+i); opcodeModSkill+i, opcodeModSkillExplicit+i);
} }

View File

@ -4,8 +4,9 @@
void ESM::CreatureStats::load (ESMReader &esm) void ESM::CreatureStats::load (ESMReader &esm)
{ {
bool intFallback = esm.getFormat() < 11;
for (int i=0; i<8; ++i) for (int i=0; i<8; ++i)
mAttributes[i].load (esm); mAttributes[i].load (esm, intFallback);
for (int i=0; i<3; ++i) for (int i=0; i<3; ++i)
mDynamic[i].load (esm); mDynamic[i].load (esm);

View File

@ -29,7 +29,7 @@ namespace ESM
TimeStamp mNextWorsening; TimeStamp mNextWorsening;
}; };
StatState<int> mAttributes[Attribute::Length]; StatState<float> mAttributes[Attribute::Length];
StatState<float> mDynamic[3]; StatState<float> mDynamic[3];
MagicEffects mMagicEffects; MagicEffects mMagicEffects;

View File

@ -31,8 +31,9 @@ void ESM::NpcStats::load (ESMReader &esm)
mDisposition = 0; mDisposition = 0;
esm.getHNOT (mDisposition, "DISP"); esm.getHNOT (mDisposition, "DISP");
bool intFallback = esm.getFormat() < 11;
for (int i=0; i<27; ++i) for (int i=0; i<27; ++i)
mSkills[i].load (esm); mSkills[i].load (esm, intFallback);
mWerewolfDeprecatedData = false; mWerewolfDeprecatedData = false;
if (esm.getFormat() < 8 && esm.peekNextSub("STBA")) if (esm.getFormat() < 8 && esm.peekNextSub("STBA"))
@ -40,17 +41,17 @@ void ESM::NpcStats::load (ESMReader &esm)
// we have deprecated werewolf skills, stored interleaved // we have deprecated werewolf skills, stored interleaved
// Load into one big vector, then remove every 2nd value // Load into one big vector, then remove every 2nd value
mWerewolfDeprecatedData = true; mWerewolfDeprecatedData = true;
std::vector<ESM::StatState<int> > skills(mSkills, mSkills + sizeof(mSkills)/sizeof(mSkills[0])); std::vector<ESM::StatState<float> > skills(mSkills, mSkills + sizeof(mSkills)/sizeof(mSkills[0]));
for (int i=0; i<27; ++i) for (int i=0; i<27; ++i)
{ {
ESM::StatState<int> skill; ESM::StatState<float> skill;
skill.load(esm); skill.load(esm, intFallback);
skills.push_back(skill); skills.push_back(skill);
} }
int i=0; int i=0;
for (std::vector<ESM::StatState<int> >::iterator it = skills.begin(); it != skills.end(); ++i) for (std::vector<ESM::StatState<float> >::iterator it = skills.begin(); it != skills.end(); ++i)
{ {
if (i%2 == 1) if (i%2 == 1)
it = skills.erase(it); it = skills.erase(it);
@ -68,7 +69,7 @@ void ESM::NpcStats::load (ESMReader &esm)
{ {
ESM::StatState<int> dummy; ESM::StatState<int> dummy;
for (int i=0; i<8; ++i) for (int i=0; i<8; ++i)
dummy.load(esm); dummy.load(esm, intFallback);
mWerewolfDeprecatedData = true; mWerewolfDeprecatedData = true;
} }

View File

@ -31,7 +31,7 @@ namespace ESM
std::map<std::string, Faction> mFactions; // lower case IDs std::map<std::string, Faction> mFactions; // lower case IDs
int mDisposition; int mDisposition;
StatState<int> mSkills[27]; StatState<float> mSkills[27];
int mBounty; int mBounty;
int mReputation; int mReputation;
int mWerewolfKills; int mWerewolfKills;

View File

@ -43,12 +43,13 @@ void ESM::Player::load (ESMReader &esm)
checkPrevItems = false; checkPrevItems = false;
} }
bool intFallback = esm.getFormat() < 11;
if (esm.hasMoreSubs()) if (esm.hasMoreSubs())
{ {
for (int i=0; i<ESM::Attribute::Length; ++i) for (int i=0; i<ESM::Attribute::Length; ++i)
mSaveAttributes[i].load(esm); mSaveAttributes[i].load(esm, intFallback);
for (int i=0; i<ESM::Skill::Length; ++i) for (int i=0; i<ESM::Skill::Length; ++i)
mSaveSkills[i].load(esm); mSaveSkills[i].load(esm, intFallback);
} }
} }

View File

@ -31,8 +31,8 @@ namespace ESM
int mCurrentCrimeId; int mCurrentCrimeId;
int mPaidCrimeId; int mPaidCrimeId;
StatState<int> mSaveAttributes[ESM::Attribute::Length]; StatState<float> mSaveAttributes[ESM::Attribute::Length];
StatState<int> mSaveSkills[ESM::Skill::Length]; StatState<float> mSaveSkills[ESM::Skill::Length];
typedef std::map<std::string, std::string> PreviousItems; // previous equipped items, needed for bound spells typedef std::map<std::string, std::string> PreviousItems; // previous equipped items, needed for bound spells
PreviousItems mPreviousItems; PreviousItems mPreviousItems;

View File

@ -5,7 +5,7 @@
#include "defs.hpp" #include "defs.hpp"
unsigned int ESM::SavedGame::sRecordId = ESM::REC_SAVE; unsigned int ESM::SavedGame::sRecordId = ESM::REC_SAVE;
int ESM::SavedGame::sCurrentFormat = 10; int ESM::SavedGame::sCurrentFormat = 11;
void ESM::SavedGame::load (ESMReader &esm) void ESM::SavedGame::load (ESMReader &esm)
{ {

View File

@ -9,19 +9,44 @@ namespace ESM
StatState<T>::StatState() : mBase(0), mMod(0), mCurrent(0), mDamage(0), mProgress(0) {} StatState<T>::StatState() : mBase(0), mMod(0), mCurrent(0), mDamage(0), mProgress(0) {}
template<typename T> template<typename T>
void StatState<T>::load(ESMReader &esm) void StatState<T>::load(ESMReader &esm, bool intFallback)
{ {
esm.getHNT(mBase, "STBA"); // We changed stats values from integers to floats; ensure backwards compatibility
if (intFallback)
{
int base = 0;
esm.getHNT(base, "STBA");
mBase = static_cast<float>(base);
mMod = 0; int mod = 0;
esm.getHNOT(mMod, "STMO"); esm.getHNOT(mod, "STMO");
mCurrent = 0; mMod = static_cast<float>(mod);
esm.getHNOT(mCurrent, "STCU");
// mDamage was changed to a float; ensure backwards compatibility int current = 0;
T oldDamage = 0; esm.getHNOT(current, "STCU");
esm.getHNOT(oldDamage, "STDA"); mCurrent = static_cast<float>(current);
mDamage = static_cast<float>(oldDamage);
// mDamage was changed to a float; ensure backwards compatibility
int oldDamage = 0;
esm.getHNOT(oldDamage, "STDA");
mDamage = static_cast<float>(oldDamage);
}
else
{
mBase = 0;
esm.getHNT(mBase, "STBA");
mMod = 0;
esm.getHNOT(mMod, "STMO");
mCurrent = 0;
esm.getHNOT(mCurrent, "STCU");
mDamage = 0;
esm.getHNOT(mDamage, "STDF");
mProgress = 0;
}
esm.getHNOT(mDamage, "STDF"); esm.getHNOT(mDamage, "STDF");

View File

@ -20,7 +20,7 @@ namespace ESM
StatState(); StatState();
void load (ESMReader &esm); void load (ESMReader &esm, bool intFallback = false);
void save (ESMWriter &esm) const; void save (ESMWriter &esm) const;
}; };
} }