forked from teamnwah/openmw-tes3coop
Implement Damage/restore skill/attribute effects. Use dedicated classes for skill and attribute values (instead of Stat<T>) since there are some important differences.
This commit is contained in:
parent
32ff3b530c
commit
b42240be6d
14 changed files with 126 additions and 72 deletions
|
@ -210,7 +210,7 @@ namespace
|
|||
+ 5
|
||||
+ raceBonus
|
||||
+ specBonus
|
||||
+ static_cast<int>((level-1) * (majorMultiplier + specMultiplier)), 100.0f));
|
||||
+ static_cast<int>((level-1) * (majorMultiplier + specMultiplier)), 100));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,7 +65,7 @@ namespace MWGui
|
|||
getWidget(attribute, std::string("Attribute") + boost::lexical_cast<std::string>(idx));
|
||||
mAttributeWidgets.insert(std::make_pair(static_cast<int>(ESM::Attribute::sAttributeIds[idx]), attribute));
|
||||
attribute->setAttributeId(ESM::Attribute::sAttributeIds[idx]);
|
||||
attribute->setAttributeValue(Widgets::MWAttribute::AttributeValue(0, 0));
|
||||
attribute->setAttributeValue(Widgets::MWAttribute::AttributeValue());
|
||||
}
|
||||
|
||||
// Setup skills
|
||||
|
@ -280,8 +280,8 @@ namespace MWGui
|
|||
assert(skillId >= 0 && skillId < ESM::Skill::Length);
|
||||
const std::string &skillNameId = ESM::Skill::sSkillNameIds[skillId];
|
||||
const MWMechanics::SkillValue &stat = mSkillValues.find(skillId)->second;
|
||||
float base = stat.getBase();
|
||||
float modified = stat.getModified();
|
||||
int base = stat.getBase();
|
||||
int modified = stat.getModified();
|
||||
|
||||
std::string state = "normal";
|
||||
if (modified > base)
|
||||
|
|
|
@ -359,21 +359,19 @@ namespace MWGui
|
|||
assert(skillId >= 0 && skillId < ESM::Skill::Length);
|
||||
const std::string &skillNameId = ESM::Skill::sSkillNameIds[skillId];
|
||||
const MWMechanics::SkillValue &stat = mSkillValues.find(skillId)->second;
|
||||
float base = stat.getBase();
|
||||
float modified = stat.getModified();
|
||||
int progressPercent = (modified - float(static_cast<int>(modified))) * 100;
|
||||
int base = stat.getBase();
|
||||
int modified = stat.getModified();
|
||||
int progressPercent = stat.getProgress() * 100;
|
||||
|
||||
const MWWorld::ESMStore &esmStore =
|
||||
MWBase::Environment::get().getWorld()->getStore();
|
||||
|
||||
const ESM::Skill* skill = esmStore.get<ESM::Skill>().find(skillId);
|
||||
assert(skill);
|
||||
|
||||
std::string icon = "icons\\k\\" + ESM::Skill::sIconNames[skillId];
|
||||
|
||||
const ESM::Attribute* attr =
|
||||
esmStore.get<ESM::Attribute>().find(skill->mData.mAttribute);
|
||||
assert(attr);
|
||||
|
||||
std::string state = "normal";
|
||||
if (modified > base)
|
||||
|
@ -484,7 +482,6 @@ namespace MWGui
|
|||
ESM::RankData rankData = faction->mData.mRankData[it->second+1];
|
||||
const ESM::Attribute* attr1 = store.get<ESM::Attribute>().find(faction->mData.mAttribute[0]);
|
||||
const ESM::Attribute* attr2 = store.get<ESM::Attribute>().find(faction->mData.mAttribute[1]);
|
||||
assert(attr1 && attr2);
|
||||
|
||||
text += "\n#BF9959#{" + attr1->mName + "}: " + boost::lexical_cast<std::string>(rankData.mAttribute1)
|
||||
+ ", #{" + attr2->mName + "}: " + boost::lexical_cast<std::string>(rankData.mAttribute2);
|
||||
|
|
|
@ -296,10 +296,10 @@ namespace MWGui
|
|||
const MWMechanics::NpcStats &sellerStats = MWWorld::Class::get(mPtr).getNpcStats(mPtr);
|
||||
const MWMechanics::NpcStats &playerStats = MWWorld::Class::get(playerPtr).getNpcStats(playerPtr);
|
||||
|
||||
float a1 = std::min(playerStats.getSkill(ESM::Skill::Mercantile).getModified(), 100.f);
|
||||
float a1 = std::min(playerStats.getSkill(ESM::Skill::Mercantile).getModified(), 100);
|
||||
float b1 = std::min(0.1f * playerStats.getAttribute(ESM::Attribute::Luck).getModified(), 10.f);
|
||||
float c1 = std::min(0.2f * playerStats.getAttribute(ESM::Attribute::Personality).getModified(), 10.f);
|
||||
float d1 = std::min(sellerStats.getSkill(ESM::Skill::Mercantile).getModified(), 100.f);
|
||||
float d1 = std::min(sellerStats.getSkill(ESM::Skill::Mercantile).getModified(), 100);
|
||||
float e1 = std::min(0.1f * sellerStats.getAttribute(ESM::Attribute::Luck).getModified(), 10.f);
|
||||
float f1 = std::min(0.2f * sellerStats.getAttribute(ESM::Attribute::Personality).getModified(), 10.f);
|
||||
|
||||
|
|
|
@ -178,7 +178,7 @@ namespace MWGui
|
|||
}
|
||||
if (mAttributeValueWidget)
|
||||
{
|
||||
AttributeValue::Type modified = mValue.getModified(), base = mValue.getBase();
|
||||
int modified = mValue.getModified(), base = mValue.getBase();
|
||||
static_cast<MyGUI::TextBox*>(mAttributeValueWidget)->setCaption(boost::lexical_cast<std::string>(modified));
|
||||
if (modified > base)
|
||||
mAttributeValueWidget->_setWidgetState("increased");
|
||||
|
|
|
@ -523,7 +523,7 @@ namespace MWMechanics
|
|||
// skills
|
||||
for(int i = 0;i < ESM::Skill::Length;++i)
|
||||
{
|
||||
Stat<float>& skill = npcStats.getSkill(i);
|
||||
SkillValue& skill = npcStats.getSkill(i);
|
||||
skill.setModifier(effects.get(EffectKey(ESM::MagicEffect::FortifySkill, i)).mMagnitude -
|
||||
effects.get(EffectKey(ESM::MagicEffect::DrainSkill, i)).mMagnitude -
|
||||
effects.get(EffectKey(ESM::MagicEffect::AbsorbSkill, i)).mMagnitude);
|
||||
|
|
|
@ -499,10 +499,10 @@ namespace MWMechanics
|
|||
// otherwise one would get different prices when exiting and re-entering the dialogue window...
|
||||
int clampedDisposition = std::max(0, std::min(getDerivedDisposition(ptr)
|
||||
+ MWBase::Environment::get().getDialogueManager()->getTemporaryDispositionChange(),100));
|
||||
float a = std::min(playerStats.getSkill(ESM::Skill::Mercantile).getModified(), 100.f);
|
||||
float a = std::min(playerStats.getSkill(ESM::Skill::Mercantile).getModified(), 100);
|
||||
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 = std::min(sellerStats.getSkill(ESM::Skill::Mercantile).getModified(), 100.f);
|
||||
float d = std::min(sellerStats.getSkill(ESM::Skill::Mercantile).getModified(), 100);
|
||||
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);
|
||||
|
||||
|
|
|
@ -197,34 +197,25 @@ void MWMechanics::NpcStats::useSkill (int skillIndex, const ESM::Class& class_,
|
|||
if(mIsWerewolf)
|
||||
return;
|
||||
|
||||
float base = getSkill (skillIndex).getBase();
|
||||
MWMechanics::SkillValue value = getSkill (skillIndex);
|
||||
|
||||
int level = static_cast<int> (base);
|
||||
value.setProgress(value.getProgress() + getSkillGain (skillIndex, class_, usageType));
|
||||
|
||||
base += getSkillGain (skillIndex, class_, usageType);
|
||||
|
||||
if (static_cast<int> (base)!=level)
|
||||
if (value.getProgress()>=1)
|
||||
{
|
||||
// skill leveled up
|
||||
increaseSkill(skillIndex, class_, false);
|
||||
}
|
||||
else
|
||||
getSkill (skillIndex).setBase (base);
|
||||
}
|
||||
|
||||
void MWMechanics::NpcStats::increaseSkill(int skillIndex, const ESM::Class &class_, bool preserveProgress)
|
||||
{
|
||||
float base = getSkill (skillIndex).getBase();
|
||||
int base = getSkill (skillIndex).getBase();
|
||||
|
||||
int level = static_cast<int> (base);
|
||||
|
||||
if (level >= 100)
|
||||
if (base >= 100)
|
||||
return;
|
||||
|
||||
if (preserveProgress)
|
||||
base += 1;
|
||||
else
|
||||
base = level+1;
|
||||
|
||||
// if this is a major or minor skill of the class, increase level progress
|
||||
bool levelProgress = false;
|
||||
|
@ -260,6 +251,8 @@ void MWMechanics::NpcStats::increaseSkill(int skillIndex, const ESM::Class &clas
|
|||
}
|
||||
|
||||
getSkill (skillIndex).setBase (base);
|
||||
if (!preserveProgress)
|
||||
getSkill(skillIndex).setProgress(0);
|
||||
}
|
||||
|
||||
int MWMechanics::NpcStats::getLevelProgress () const
|
||||
|
@ -387,7 +380,7 @@ void MWMechanics::NpcStats::setWerewolf (bool set)
|
|||
// Oh, Bethesda. It's "Intelligence".
|
||||
std::string name = "fWerewolf"+((i==ESM::Attribute::Intelligence) ? std::string("Intellegence") :
|
||||
ESM::Attribute::sAttributeNames[i]);
|
||||
mWerewolfAttributes[i].setModified(int(gmst.find(name)->getFloat()), 0);
|
||||
mWerewolfAttributes[i].setBase(int(gmst.find(name)->getFloat()));
|
||||
}
|
||||
|
||||
for(size_t i = 0;i < ESM::Skill::Length;i++)
|
||||
|
@ -401,7 +394,7 @@ void MWMechanics::NpcStats::setWerewolf (bool set)
|
|||
// "Mercantile"! >_<
|
||||
std::string name = "fWerewolf"+((i==ESM::Skill::Mercantile) ? std::string("Merchantile") :
|
||||
ESM::Skill::sSkillNames[i]);
|
||||
mWerewolfSkill[i].setModified(int(gmst.find(name)->getFloat()), 0);
|
||||
mWerewolfSkill[i].setBase(int(gmst.find(name)->getFloat()));
|
||||
}
|
||||
}
|
||||
mIsWerewolf = set;
|
||||
|
|
|
@ -45,8 +45,8 @@ namespace MWMechanics
|
|||
DrawState_ mDrawState;
|
||||
int mDisposition;
|
||||
unsigned int mMovementFlags;
|
||||
Stat<float> mSkill[27];
|
||||
Stat<float> mWerewolfSkill[27];
|
||||
SkillValue mSkill[27];
|
||||
SkillValue mWerewolfSkill[27];
|
||||
int mBounty;
|
||||
std::set<std::string> mExpelled;
|
||||
std::map<std::string, int> mFactionReputation;
|
||||
|
|
|
@ -135,7 +135,8 @@ namespace MWMechanics
|
|||
float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * random;
|
||||
magnitude *= magnitudeMult;
|
||||
|
||||
if (target.getClass().isActor() && !(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration))
|
||||
bool hasDuration = !(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration);
|
||||
if (target.getClass().isActor() && hasDuration)
|
||||
{
|
||||
ActiveSpells::Effect effect;
|
||||
effect.mKey = MWMechanics::EffectKey(*effectIt);
|
||||
|
@ -160,7 +161,17 @@ namespace MWMechanics
|
|||
}
|
||||
}
|
||||
else
|
||||
applyInstantEffect(target, effectIt->mEffectID, magnitude);
|
||||
applyInstantEffect(target, EffectKey(*effectIt), magnitude);
|
||||
|
||||
// HACK: Damage attribute/skill actually has a duration, even though the actual effect is instant and permanent.
|
||||
// This was probably just done to have the effect visible in the magic menu for a while
|
||||
// to notify the player they've been damaged?
|
||||
if (effectIt->mEffectID == ESM::MagicEffect::DamageAttribute
|
||||
|| effectIt->mEffectID == ESM::MagicEffect::DamageSkill
|
||||
|| effectIt->mEffectID == ESM::MagicEffect::RestoreAttribute
|
||||
|| effectIt->mEffectID == ESM::MagicEffect::RestoreSkill
|
||||
)
|
||||
applyInstantEffect(target, EffectKey(*effectIt), magnitude);
|
||||
|
||||
if (target.getClass().isActor() || magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration)
|
||||
{
|
||||
|
@ -203,8 +214,9 @@ namespace MWMechanics
|
|||
mSourceName, caster.getRefData().getHandle());
|
||||
}
|
||||
|
||||
void CastSpell::applyInstantEffect(const MWWorld::Ptr &target, short effectId, float magnitude)
|
||||
void CastSpell::applyInstantEffect(const MWWorld::Ptr &target, MWMechanics::EffectKey effect, float magnitude)
|
||||
{
|
||||
short effectId = effect.mId;
|
||||
if (!target.getClass().isActor())
|
||||
{
|
||||
if (effectId == ESM::MagicEffect::Lock)
|
||||
|
@ -227,6 +239,28 @@ namespace MWMechanics
|
|||
}
|
||||
else
|
||||
{
|
||||
if (effectId == ESM::MagicEffect::DamageAttribute || effectId == ESM::MagicEffect::RestoreAttribute)
|
||||
{
|
||||
int attribute = effect.mArg;
|
||||
AttributeValue value = target.getClass().getCreatureStats(target).getAttribute(attribute);
|
||||
if (effectId == ESM::MagicEffect::DamageAttribute)
|
||||
value.damage(magnitude);
|
||||
else
|
||||
value.restore(magnitude);
|
||||
target.getClass().getCreatureStats(target).setAttribute(attribute, value);
|
||||
}
|
||||
else if (effectId == ESM::MagicEffect::DamageSkill || effectId == ESM::MagicEffect::RestoreSkill)
|
||||
{
|
||||
if (target.getTypeName() != typeid(ESM::NPC).name())
|
||||
return;
|
||||
int skill = effect.mArg;
|
||||
SkillValue& value = target.getClass().getNpcStats(target).getSkill(skill);
|
||||
if (effectId == ESM::MagicEffect::DamageSkill)
|
||||
value.damage(magnitude);
|
||||
else
|
||||
value.restore(magnitude);
|
||||
}
|
||||
|
||||
if (effectId == ESM::MagicEffect::CurePoison)
|
||||
target.getClass().getCreatureStats(target).getActiveSpells().purgeEffect(ESM::MagicEffect::Poison);
|
||||
else if (effectId == ESM::MagicEffect::CureParalyzation)
|
||||
|
|
|
@ -203,7 +203,7 @@ namespace MWMechanics
|
|||
void inflict (const MWWorld::Ptr& target, const MWWorld::Ptr& caster,
|
||||
const ESM::EffectList& effects, ESM::RangeType range, bool reflected=false);
|
||||
|
||||
void applyInstantEffect (const MWWorld::Ptr& target, short effectId, float magnitude);
|
||||
void applyInstantEffect (const MWWorld::Ptr& target, MWMechanics::EffectKey effect, float magnitude);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -206,8 +206,45 @@ namespace MWMechanics
|
|||
return !(left==right);
|
||||
}
|
||||
|
||||
typedef Stat<int> AttributeValue;
|
||||
typedef Stat<float> SkillValue;
|
||||
class AttributeValue
|
||||
{
|
||||
int mBase;
|
||||
int mModifier;
|
||||
int mDamage;
|
||||
|
||||
public:
|
||||
AttributeValue() : mBase(0), mModifier(0), mDamage(0) {}
|
||||
|
||||
int getModified() const { return std::max(0, mBase - mDamage + mModifier); }
|
||||
int getBase() const { return mBase; }
|
||||
int getModifier() const { return mModifier; }
|
||||
|
||||
void setBase(int base) { mBase = std::max(0, base); }
|
||||
void setModifier(int mod) { mModifier = mod; }
|
||||
|
||||
void damage(int damage) { mDamage += damage; }
|
||||
void restore(int amount) { mDamage -= std::min(mDamage, amount); }
|
||||
int getDamage() const { return mDamage; }
|
||||
};
|
||||
|
||||
class SkillValue : public AttributeValue
|
||||
{
|
||||
float mProgress;
|
||||
public:
|
||||
float getProgress() const { return mProgress; }
|
||||
void setProgress(float progress) { mProgress = progress; }
|
||||
};
|
||||
|
||||
inline bool operator== (const AttributeValue& left, const AttributeValue& right)
|
||||
{
|
||||
return left.getBase() == right.getBase()
|
||||
&& left.getModifier() == right.getModifier()
|
||||
&& left.getDamage() == right.getDamage();
|
||||
}
|
||||
inline bool operator!= (const AttributeValue& left, const AttributeValue& right)
|
||||
{
|
||||
return !(left == right);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -125,7 +125,7 @@ namespace MWScript
|
|||
runtime.pop();
|
||||
|
||||
MWMechanics::AttributeValue attribute = ptr.getClass().getCreatureStats(ptr).getAttribute(mIndex);
|
||||
attribute.setModified (value, 0);
|
||||
attribute.setBase (value - (attribute.getModified() - attribute.getBase()));
|
||||
ptr.getClass().getCreatureStats(ptr).setAttribute(mIndex, attribute);
|
||||
}
|
||||
};
|
||||
|
@ -150,11 +150,7 @@ namespace MWScript
|
|||
.getCreatureStats(ptr)
|
||||
.getAttribute(mIndex);
|
||||
|
||||
value +=
|
||||
attribute.getModified();
|
||||
|
||||
attribute
|
||||
.setModified (value, 0, 100);
|
||||
attribute.setBase (std::min(100, attribute.getBase() + value));
|
||||
ptr.getClass().getCreatureStats(ptr).setAttribute(mIndex, attribute);
|
||||
}
|
||||
};
|
||||
|
@ -346,12 +342,10 @@ namespace MWScript
|
|||
const ESM::Class& class_ =
|
||||
*MWBase::Environment::get().getWorld()->getStore().get<ESM::Class>().find (ref->mBase->mClass);
|
||||
|
||||
float level = 0;
|
||||
float progress = std::modf (stats.getSkill (mIndex).getBase(), &level);
|
||||
float level = stats.getSkill(mIndex).getBase();
|
||||
float progress = stats.getSkill(mIndex).getProgress();
|
||||
|
||||
float modifier = stats.getSkill (mIndex).getModifier();
|
||||
|
||||
int newLevel = static_cast<int> (value-modifier);
|
||||
int newLevel = value - (stats.getSkill(mIndex).getModified() - stats.getSkill(mIndex).getBase());
|
||||
|
||||
if (newLevel<0)
|
||||
newLevel = 0;
|
||||
|
@ -362,8 +356,8 @@ namespace MWScript
|
|||
if (progress>=1)
|
||||
progress = 0.999999999;
|
||||
|
||||
stats.getSkill (mIndex).set (newLevel + progress);
|
||||
stats.getSkill (mIndex).setModifier (modifier);
|
||||
stats.getSkill (mIndex).setBase (newLevel);
|
||||
stats.getSkill (mIndex).setProgress(progress);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -383,11 +377,10 @@ namespace MWScript
|
|||
Interpreter::Type_Integer value = runtime[0].mInteger;
|
||||
runtime.pop();
|
||||
|
||||
value += MWWorld::Class::get (ptr).getNpcStats (ptr).getSkill (mIndex).
|
||||
getModified();
|
||||
MWMechanics::NpcStats& stats = ptr.getClass().getNpcStats(ptr);
|
||||
|
||||
MWWorld::Class::get (ptr).getNpcStats (ptr).getSkill (mIndex).
|
||||
setModified (value, 0, 100);
|
||||
stats.getSkill(mIndex).
|
||||
setBase (std::min(100, stats.getSkill(mIndex).getBase() + value));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -2000,7 +2000,7 @@ namespace MWWorld
|
|||
const Store<ESM::GameSetting> &gmst = getStore().get<ESM::GameSetting>();
|
||||
MWMechanics::NpcStats &stats = Class::get(actor).getNpcStats(actor);
|
||||
|
||||
stats.getSkill(ESM::Skill::Acrobatics).setModified(gmst.find("fWerewolfAcrobatics")->getFloat(), 0);
|
||||
stats.getSkill(ESM::Skill::Acrobatics).setBase(gmst.find("fWerewolfAcrobatics")->getFloat());
|
||||
}
|
||||
|
||||
bool World::getGodModeState()
|
||||
|
|
Loading…
Reference in a new issue