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

pull/578/head
Andrei Kortunov 6 years ago
parent 2eb9d4ad4e
commit 5468fcb29f

@ -5,6 +5,7 @@
Bug #2311: Targeted scripts are not properly supported on non-unique RefIDs
Bug #3676: NiParticleColorModifier isn't applied properly
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 #4774: Guards are ignorant of an invisible player that tries to attack them
Bug #5108: Savegame bloating due to inefficient fog textures format

@ -276,7 +276,7 @@ namespace MWClass
const MWWorld::LiveCellRef<ESM::Armor> *ref = ptr.get<ESM::Armor>();
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();
int iBaseArmorSkill = world->getStore().get<ESM::GameSetting>().find("iBaseArmorSkill")->mValue.getInteger();

@ -605,7 +605,7 @@ namespace MWClass
float Creature::getCapacity (const MWWorld::Ptr& ptr) const
{
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
@ -745,7 +745,7 @@ namespace MWClass
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 =
ptr.get<ESM::Creature>();

@ -108,7 +108,7 @@ namespace MWClass
virtual bool canSwim (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)
virtual int getBloodTexture (const MWWorld::ConstPtr& ptr) const;

@ -125,7 +125,7 @@ namespace MWClass
}
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 =
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fWortChanceValue")->mValue.getFloat();

@ -127,8 +127,8 @@ namespace
}
// initial health
int strength = creatureStats.getAttribute(ESM::Attribute::Strength).getBase();
int endurance = creatureStats.getAttribute(ESM::Attribute::Endurance).getBase();
float strength = creatureStats.getAttribute(ESM::Attribute::Strength).getBase();
float endurance = creatureStats.getAttribute(ESM::Attribute::Endurance).getBase();
int multiplier = 3;
@ -1011,7 +1011,7 @@ namespace MWClass
gmst.fJumpEncumbranceMultiplier->mValue.getFloat() *
(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;
if(a > 50.0f)
{
@ -1136,7 +1136,7 @@ namespace MWClass
float fUnarmoredBase1 = store.find("fUnarmoredBase1")->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];
for(int i = 0;i < MWWorld::InventoryStore::Slots;i++)
@ -1283,7 +1283,7 @@ namespace MWClass
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();
}

@ -129,7 +129,7 @@ namespace MWClass
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)
virtual int getBloodTexture (const MWWorld::ConstPtr& ptr) const;

@ -95,9 +95,9 @@ namespace MWGui
MWMechanics::SkillValue& value = player.getClass().getNpcStats(player).getSkill(skill);
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
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>();

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

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

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

@ -74,11 +74,11 @@ namespace MWGui
mPlayerGold->setCaptionWithReplacing("#{sGold}: " + MyGUI::utility::toString(playerGold));
// 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)
{
int value = actor.getClass().getSkill(actor, i);
float value = actor.getClass().getSkill(actor, i);
skills.push_back(std::make_pair(i, value));
}

@ -132,7 +132,7 @@ void getRestorationPerHourOfSleep (const MWWorld::Ptr& ptr, float& health, float
MWMechanics::CreatureStats& stats = ptr.getClass().getCreatureStats (ptr);
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;
float fRestMagicMult = settings.find("fRestMagicMult")->mValue.getFloat ();
@ -765,7 +765,7 @@ namespace MWMechanics
{
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;
if (ptr == getPlayer())
@ -844,7 +844,7 @@ namespace MWMechanics
float fFatigueReturnMult = settings.find("fFatigueReturnMult")->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);
if (normalizedEncumbrance > 1)
@ -871,7 +871,7 @@ namespace MWMechanics
return;
// 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>();
static const float fFatigueReturnBase = settings.find("fFatigueReturnBase")->mValue.getFloat ();
static const float fFatigueReturnMult = settings.find("fFatigueReturnMult")->mValue.getFloat ();

@ -468,7 +468,7 @@ MWMechanics::Alchemy::TEffectsIterator MWMechanics::Alchemy::endEffects() const
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 =
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fWortChanceValue")->mValue.getFloat();
return (potionEffectIndex <= 1 && alchemySkill >= fWortChanceValue)

@ -2128,7 +2128,7 @@ void CharacterController::update(float duration, bool animationOnly)
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 (!godmode)

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

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

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

@ -688,10 +688,10 @@ namespace MWMechanics
// 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...
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 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 f = std::min(0.2f * sellerStats.getAttribute(ESM::Attribute::Personality).getModified(), 10.f);
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 fSneakBootMult = store.find("fSneakBootMult")->mValue.getFloat();
float sneak = static_cast<float>(ptr.getClass().getSkill(ptr, ESM::Skill::Sneak));
int agility = stats.getAttribute(ESM::Attribute::Agility).getModified();
int luck = stats.getAttribute(ESM::Attribute::Luck).getModified();
float agility = stats.getAttribute(ESM::Attribute::Agility).getModified();
float luck = stats.getAttribute(ESM::Attribute::Luck).getModified();
float bootWeight = 0;
if (ptr.getClass().isNpc() && MWBase::Environment::get().getWorld()->isOnGround(ptr))
{
@ -1645,10 +1645,10 @@ namespace MWMechanics
float x = sneakTerm * distTerm * stats.getFatigueTerm() + chameleon + invisibility;
CreatureStats& observerStats = observer.getClass().getCreatureStats(observer);
int obsAgility = observerStats.getAttribute(ESM::Attribute::Agility).getModified();
int obsLuck = observerStats.getAttribute(ESM::Attribute::Luck).getModified();
float obsAgility = observerStats.getAttribute(ESM::Attribute::Agility).getModified();
float obsLuck = observerStats.getAttribute(ESM::Attribute::Luck).getModified();
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;

@ -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)
{
int base = getSkill (skillIndex).getBase();
float base = getSkill (skillIndex).getBase();
if (base >= 100)
if (base >= 100.f)
return;
base += 1;
@ -299,7 +299,7 @@ void MWMechanics::NpcStats::levelUp()
for (int i=0; i<ESM::Attribute::Length; ++i)
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
// 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()
{
const int endurance = getAttribute(ESM::Attribute::Endurance).getBase();
const int strength = getAttribute(ESM::Attribute::Strength).getBase();
const float endurance = getAttribute(ESM::Attribute::Endurance).getBase();
const float strength = getAttribute(ESM::Attribute::Strength).getBase();
setHealth(floor(0.5f * (strength + endurance)));
}

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

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

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

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

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

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

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

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

@ -421,7 +421,7 @@ namespace MWWorld
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");
}

@ -321,7 +321,7 @@ namespace MWWorld
bool isPureLandCreature(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)
const;

@ -284,12 +284,12 @@ void MWWorld::InventoryStore::autoEquipWeapon (const MWWorld::Ptr& actor, TSlots
// rate weapon
for (int i = 0; i < static_cast<int>(weaponSkillsLength); ++i)
{
int max = 0;
float max = 0;
int maxWeaponSkill = -1;
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])
{
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 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);
for (ContainerStoreIterator iter (begin(ContainerStore::Type_Clothing | ContainerStore::Type_Armor)); iter!=end(); ++iter)

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

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

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

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

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

@ -43,12 +43,13 @@ void ESM::Player::load (ESMReader &esm)
checkPrevItems = false;
}
bool intFallback = esm.getFormat() < 11;
if (esm.hasMoreSubs())
{
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)
mSaveSkills[i].load(esm);
mSaveSkills[i].load(esm, intFallback);
}
}

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

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

@ -9,19 +9,44 @@ namespace ESM
StatState<T>::StatState() : mBase(0), mMod(0), mCurrent(0), mDamage(0), mProgress(0) {}
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;
esm.getHNOT(mMod, "STMO");
mCurrent = 0;
esm.getHNOT(mCurrent, "STCU");
int mod = 0;
esm.getHNOT(mod, "STMO");
mMod = static_cast<float>(mod);
// mDamage was changed to a float; ensure backwards compatibility
T oldDamage = 0;
esm.getHNOT(oldDamage, "STDA");
mDamage = static_cast<float>(oldDamage);
int current = 0;
esm.getHNOT(current, "STCU");
mCurrent = static_cast<float>(current);
// 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");

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

Loading…
Cancel
Save