Implement magic effect script instructions (Feature #1489)

deque
scrawl 11 years ago
parent d8943aef2f
commit 2db50da8dd

@ -357,6 +357,7 @@ namespace MWMechanics
CreatureStats& creatureStats = creature.getClass().getCreatureStats (creature); CreatureStats& creatureStats = creature.getClass().getCreatureStats (creature);
if (creatureStats.isDead()) if (creatureStats.isDead())
return; return;
MagicEffects now = creatureStats.getSpells().getMagicEffects(); MagicEffects now = creatureStats.getSpells().getMagicEffects();
if (creature.getTypeName()==typeid (ESM::NPC).name()) if (creature.getTypeName()==typeid (ESM::NPC).name())
@ -367,11 +368,7 @@ namespace MWMechanics
now += creatureStats.getActiveSpells().getMagicEffects(); now += creatureStats.getActiveSpells().getMagicEffects();
//MagicEffects diff = MagicEffects::diff (creatureStats.getMagicEffects(), now); creatureStats.modifyMagicEffects(now);
creatureStats.setMagicEffects(now);
// TODO apply diff to other stats
} }
void Actors::calculateDynamicStats (const MWWorld::Ptr& ptr) void Actors::calculateDynamicStats (const MWWorld::Ptr& ptr)
@ -1297,7 +1294,7 @@ namespace MWMechanics
// Reset magic effects and recalculate derived effects // Reset magic effects and recalculate derived effects
// One case where we need this is to make sure bound items are removed upon death // One case where we need this is to make sure bound items are removed upon death
stats.setMagicEffects(MWMechanics::MagicEffects()); stats.modifyMagicEffects(MWMechanics::MagicEffects());
stats.getActiveSpells().clear(); stats.getActiveSpells().clear();
calculateCreatureStatModifiers(iter->first, 0); calculateCreatureStatModifiers(iter->first, 0);

@ -211,13 +211,13 @@ namespace MWMechanics
mActiveSpells = active; mActiveSpells = active;
} }
void CreatureStats::setMagicEffects(const MagicEffects &effects) void CreatureStats::modifyMagicEffects(const MagicEffects &effects)
{ {
if (effects.get(ESM::MagicEffect::FortifyMaximumMagicka).getMagnitude() if (effects.get(ESM::MagicEffect::FortifyMaximumMagicka).getModifier()
!= mMagicEffects.get(ESM::MagicEffect::FortifyMaximumMagicka).getMagnitude()) != mMagicEffects.get(ESM::MagicEffect::FortifyMaximumMagicka).getModifier())
mRecalcDynamicStats = true; mRecalcDynamicStats = true;
mMagicEffects = effects; mMagicEffects.setModifiers(effects);
} }
void CreatureStats::setAttackingOrSpell(bool attackingOrSpell) void CreatureStats::setAttackingOrSpell(bool attackingOrSpell)

@ -141,7 +141,8 @@ namespace MWMechanics
void setActiveSpells(const ActiveSpells &active); void setActiveSpells(const ActiveSpells &active);
void setMagicEffects(const MagicEffects &effects); /// Set Modifier for each magic effect according to \a effects. Does not touch Base values.
void modifyMagicEffects(const MagicEffects &effects);
void setAttackingOrSpell(bool attackingOrSpell); void setAttackingOrSpell(bool attackingOrSpell);

@ -42,23 +42,45 @@ namespace MWMechanics
float EffectParam::getMagnitude() const float EffectParam::getMagnitude() const
{ {
return mMagnitude; return mBase + mModifier;
} }
EffectParam::EffectParam() : mMagnitude (0) {} void EffectParam::modifyBase(int diff)
{
mBase += diff;
}
void EffectParam::setModifier(float mod)
{
mModifier = mod;
}
float EffectParam::getModifier() const
{
return mModifier;
}
EffectParam::EffectParam() : mModifier (0), mBase(0) {}
EffectParam& EffectParam::operator+= (const EffectParam& param) EffectParam& EffectParam::operator+= (const EffectParam& param)
{ {
mMagnitude += param.mMagnitude; mModifier += param.mModifier;
mBase += param.mBase;
return *this; return *this;
} }
EffectParam& EffectParam::operator-= (const EffectParam& param) EffectParam& EffectParam::operator-= (const EffectParam& param)
{ {
mMagnitude -= param.mMagnitude; mModifier -= param.mModifier;
mBase -= param.mBase;
return *this; return *this;
} }
void MagicEffects::remove(const EffectKey &key)
{
mCollection.erase(key);
}
void MagicEffects::add (const EffectKey& key, const EffectParam& param) void MagicEffects::add (const EffectKey& key, const EffectParam& param)
{ {
Collection::iterator iter = mCollection.find (key); Collection::iterator iter = mCollection.find (key);
@ -73,6 +95,24 @@ namespace MWMechanics
} }
} }
void MagicEffects::modifyBase(const EffectKey &key, int diff)
{
mCollection[key].modifyBase(diff);
}
void MagicEffects::setModifiers(const MagicEffects &effects)
{
for (Collection::iterator it = mCollection.begin(); it != mCollection.end(); ++it)
{
it->second.setModifier(effects.get(it->first).getModifier());
}
for (Collection::const_iterator it = effects.begin(); it != effects.end(); ++it)
{
mCollection[it->first].setModifier(it->second.getModifier());
}
}
MagicEffects& MagicEffects::operator+= (const MagicEffects& effects) MagicEffects& MagicEffects::operator+= (const MagicEffects& effects)
{ {
if (this==&effects) if (this==&effects)

@ -30,15 +30,23 @@ namespace MWMechanics
{ {
private: private:
// Note usually this would be int, but applying partial resistance might introduce a decimal point. // Note usually this would be int, but applying partial resistance might introduce a decimal point.
float mMagnitude; float mModifier;
int mBase;
public: public:
/// Get the total magnitude including base and modifier. /// Get the total magnitude including base and modifier.
float getMagnitude() const; float getMagnitude() const;
void setModifier(float mod);
float getModifier() const;
/// Change mBase by \a diff
void modifyBase(int diff);
EffectParam(); EffectParam();
EffectParam(float magnitude) : mMagnitude(magnitude) {} EffectParam(float magnitude) : mModifier(magnitude), mBase(0) {}
EffectParam& operator+= (const EffectParam& param); EffectParam& operator+= (const EffectParam& param);
@ -83,6 +91,12 @@ namespace MWMechanics
Collection::const_iterator end() const { return mCollection.end(); } Collection::const_iterator end() const { return mCollection.end(); }
void add (const EffectKey& key, const EffectParam& param); void add (const EffectKey& key, const EffectParam& param);
void remove (const EffectKey& key);
void modifyBase (const EffectKey& key, int diff);
/// Copy Modifier values from \a effects, but keep original mBase values.
void setModifiers(const MagicEffects& effects);
MagicEffects& operator+= (const MagicEffects& effects); MagicEffects& operator+= (const MagicEffects& effects);

@ -68,7 +68,7 @@ namespace MWMechanics
// reset // reset
creatureStats.setLevel(player->mNpdt52.mLevel); creatureStats.setLevel(player->mNpdt52.mLevel);
creatureStats.getSpells().clear(); creatureStats.getSpells().clear();
creatureStats.setMagicEffects(MagicEffects()); creatureStats.modifyMagicEffects(MagicEffects());
for (int i=0; i<27; ++i) for (int i=0; i<27; ++i)
npcStats.getSkill (i).setBase (player->mNpdt52.mSkills[i]); npcStats.getSkill (i).setBase (player->mNpdt52.mSkills[i]);

@ -421,5 +421,15 @@ op 0x200025c: ClearForceMoveJump
op 0x200025d: ClearForceMoveJump, explicit reference op 0x200025d: ClearForceMoveJump, explicit reference
op 0x200025e: ForceMoveJump op 0x200025e: ForceMoveJump
op 0x200025f: ForceMoveJump, explicit reference op 0x200025f: ForceMoveJump, explicit reference
op 0x2000260: GetForceJump
op 0x2000261: GetForceJump, explicit reference
op 0x2000262: GetForceMoveJump
op 0x2000263: GetForceMoveJump, explicit reference
op 0x2000264-0x200027b: GetMagicEffect
op 0x200027c-0x2000293: GetMagicEffect, explicit
op 0x2000294-0x20002ab: SetMagicEffect
op 0x20002ac-0x20002c3: SetMagicEffect, explicit
op 0x20002c4-0x20002db: ModMagicEffect
op 0x20002dc-0x20002f3: ModMagicEffect, explicit
opcodes 0x2000260-0x3ffffff unused opcodes 0x20002f4-0x3ffffff unused

@ -1176,6 +1176,91 @@ namespace MWScript
} }
}; };
template <class R>
class OpGetMagicEffect : public Interpreter::Opcode0
{
int mPositiveEffect;
int mNegativeEffect;
public:
OpGetMagicEffect (int positiveEffect, int negativeEffect)
: mPositiveEffect(positiveEffect)
, mNegativeEffect(negativeEffect)
{
}
virtual void execute (Interpreter::Runtime& runtime)
{
MWWorld::Ptr ptr = R()(runtime);
MWMechanics::CreatureStats& stats = ptr.getClass().getCreatureStats(ptr);
float currentValue = stats.getMagicEffects().get(mPositiveEffect).getMagnitude();
if (mNegativeEffect != -1)
currentValue -= stats.getMagicEffects().get(mNegativeEffect).getMagnitude();
int ret = static_cast<int>(currentValue);
runtime.push(ret);
}
};
template <class R>
class OpSetMagicEffect : public Interpreter::Opcode0
{
int mPositiveEffect;
int mNegativeEffect;
public:
OpSetMagicEffect (int positiveEffect, int negativeEffect)
: mPositiveEffect(positiveEffect)
, mNegativeEffect(negativeEffect)
{
}
virtual void execute(Interpreter::Runtime &runtime)
{
MWWorld::Ptr ptr = R()(runtime);
MWMechanics::CreatureStats& stats = ptr.getClass().getCreatureStats(ptr);
float currentValue = stats.getMagicEffects().get(mPositiveEffect).getMagnitude();
if (mNegativeEffect != -1)
currentValue -= stats.getMagicEffects().get(mNegativeEffect).getMagnitude();
currentValue = int(currentValue);
int arg = runtime[0].mInteger;
runtime.pop();
stats.getMagicEffects().modifyBase(mPositiveEffect, (arg - currentValue));
}
};
template <class R>
class OpModMagicEffect : public Interpreter::Opcode0
{
int mPositiveEffect;
int mNegativeEffect;
public:
OpModMagicEffect (int positiveEffect, int negativeEffect)
: mPositiveEffect(positiveEffect)
, mNegativeEffect(negativeEffect)
{
}
virtual void execute(Interpreter::Runtime &runtime)
{
MWWorld::Ptr ptr = R()(runtime);
MWMechanics::CreatureStats& stats = ptr.getClass().getCreatureStats(ptr);
int arg = runtime[0].mInteger;
runtime.pop();
stats.getMagicEffects().modifyBase(mPositiveEffect, arg);
}
};
struct MagicEffect
{
int mPositiveEffect;
int mNegativeEffect;
};
void installOpcodes (Interpreter::Interpreter& interpreter) void installOpcodes (Interpreter::Interpreter& interpreter)
{ {
for (int i=0; i<Compiler::Stats::numberOfAttributes; ++i) for (int i=0; i<Compiler::Stats::numberOfAttributes; ++i)
@ -1320,6 +1405,48 @@ namespace MWScript
interpreter.installSegment5 (Compiler::Stats::opcodeSetWerewolfAcrobaticsExplicit, new OpSetWerewolfAcrobatics<ExplicitRef>); interpreter.installSegment5 (Compiler::Stats::opcodeSetWerewolfAcrobaticsExplicit, new OpSetWerewolfAcrobatics<ExplicitRef>);
interpreter.installSegment5 (Compiler::Stats::opcodeGetStat, new OpGetStat<ImplicitRef>); interpreter.installSegment5 (Compiler::Stats::opcodeGetStat, new OpGetStat<ImplicitRef>);
interpreter.installSegment5 (Compiler::Stats::opcodeGetStatExplicit, new OpGetStat<ExplicitRef>); interpreter.installSegment5 (Compiler::Stats::opcodeGetStatExplicit, new OpGetStat<ExplicitRef>);
static const MagicEffect sMagicEffects[] = {
{ ESM::MagicEffect::ResistMagicka, ESM::MagicEffect::WeaknessToMagicka },
{ ESM::MagicEffect::ResistFire, ESM::MagicEffect::WeaknessToFire },
{ ESM::MagicEffect::ResistFrost, ESM::MagicEffect::WeaknessToFrost },
{ ESM::MagicEffect::ResistShock, ESM::MagicEffect::WeaknessToShock },
{ ESM::MagicEffect::ResistCommonDisease, ESM::MagicEffect::WeaknessToCommonDisease },
{ ESM::MagicEffect::ResistBlightDisease, ESM::MagicEffect::WeaknessToBlightDisease },
{ ESM::MagicEffect::ResistCorprusDisease, ESM::MagicEffect::WeaknessToCorprusDisease },
{ ESM::MagicEffect::ResistPoison, ESM::MagicEffect::WeaknessToPoison },
{ ESM::MagicEffect::ResistParalysis, -1 },
{ ESM::MagicEffect::ResistNormalWeapons, ESM::MagicEffect::WeaknessToNormalWeapons },
{ ESM::MagicEffect::WaterBreathing, -1 },
{ ESM::MagicEffect::Chameleon, -1 },
{ ESM::MagicEffect::WaterWalking, -1 },
{ ESM::MagicEffect::SwiftSwim, -1 },
{ ESM::MagicEffect::Jump, -1 },
{ ESM::MagicEffect::Levitate, -1 },
{ ESM::MagicEffect::Shield, -1 },
{ ESM::MagicEffect::Sound, -1 },
{ ESM::MagicEffect::Silence, -1 },
{ ESM::MagicEffect::Blind, -1 },
{ ESM::MagicEffect::Paralyze, -1 },
{ ESM::MagicEffect::Invisibility, -1 },
{ ESM::MagicEffect::FortifyAttack, -1 },
{ ESM::MagicEffect::Sanctuary, -1 },
};
for (int i=0; i<24; ++i)
{
int positive = sMagicEffects[i].mPositiveEffect;
int negative = sMagicEffects[i].mNegativeEffect;
interpreter.installSegment5 (Compiler::Stats::opcodeGetMagicEffect+i, new OpGetMagicEffect<ImplicitRef> (positive, negative));
interpreter.installSegment5 (Compiler::Stats::opcodeGetMagicEffectExplicit+i, new OpGetMagicEffect<ExplicitRef> (positive, negative));
interpreter.installSegment5 (Compiler::Stats::opcodeSetMagicEffect+i, new OpSetMagicEffect<ImplicitRef> (positive, negative));
interpreter.installSegment5 (Compiler::Stats::opcodeSetMagicEffectExplicit+i, new OpSetMagicEffect<ExplicitRef> (positive, negative));
interpreter.installSegment5 (Compiler::Stats::opcodeModMagicEffect+i, new OpModMagicEffect<ImplicitRef> (positive, negative));
interpreter.installSegment5 (Compiler::Stats::opcodeModMagicEffectExplicit+i, new OpModMagicEffect<ExplicitRef> (positive, negative));
}
} }
} }
} }

@ -640,7 +640,7 @@ void MWWorld::InventoryStore::rechargeItems(float duration)
void MWWorld::InventoryStore::purgeEffect(short effectId) void MWWorld::InventoryStore::purgeEffect(short effectId)
{ {
mMagicEffects.add(MWMechanics::EffectKey(effectId), -mMagicEffects.get(MWMechanics::EffectKey(effectId)).getMagnitude()); mMagicEffects.remove(MWMechanics::EffectKey(effectId));
} }
void MWWorld::InventoryStore::clear() void MWWorld::InventoryStore::clear()

@ -370,6 +370,16 @@ namespace Compiler
"mercantile", "speechcraft", "handtohand" "mercantile", "speechcraft", "handtohand"
}; };
static const char *magicEffects[numberOfMagicEffects] =
{
"resistmagicka", "resistfire", "resistfrost", "resistshock",
"resistdisease", "resistblight", "resistcorprus", "resistpoison",
"resistparalysis", "resistnormalweapons", "waterbreathing", "chameleon",
"waterwalking", "swimspeed", "superjump", "flying",
"armorbonus", "castpenalty", "silence", "blindness",
"paralysis", "invisible", "attackbonus", "defendbonus"
};
std::string get ("get"); std::string get ("get");
std::string set ("set"); std::string set ("set");
std::string mod ("mod"); std::string mod ("mod");
@ -418,6 +428,18 @@ namespace Compiler
opcodeModSkill+i, opcodeModSkillExplicit+i); opcodeModSkill+i, opcodeModSkillExplicit+i);
} }
for (int i=0; i<numberOfMagicEffects; ++i)
{
extensions.registerFunction (get + magicEffects[i], 'l', "",
opcodeGetMagicEffect+i, opcodeGetMagicEffectExplicit+i);
extensions.registerInstruction (set + magicEffects[i], "l",
opcodeSetMagicEffect+i, opcodeSetMagicEffectExplicit+i);
extensions.registerInstruction(mod + magicEffects[i], "l",
opcodeModMagicEffect+i, opcodeModMagicEffectExplicit+i);
}
extensions.registerFunction ("getpccrimelevel", 'f', "", opcodeGetPCCrimeLevel); extensions.registerFunction ("getpccrimelevel", 'f', "", opcodeGetPCCrimeLevel);
extensions.registerInstruction ("setpccrimelevel", "f", opcodeSetPCCrimeLevel); extensions.registerInstruction ("setpccrimelevel", "f", opcodeSetPCCrimeLevel);
extensions.registerInstruction ("modpccrimelevel", "f", opcodeModPCCrimeLevel); extensions.registerInstruction ("modpccrimelevel", "f", opcodeModPCCrimeLevel);

@ -322,6 +322,8 @@ namespace Compiler
const int numberOfDynamics = 3; const int numberOfDynamics = 3;
const int numberOfSkills = 27; const int numberOfSkills = 27;
const int numberOfMagicEffects = 24;
const int opcodeGetAttribute = 0x2000027; const int opcodeGetAttribute = 0x2000027;
const int opcodeGetAttributeExplicit = 0x200002f; const int opcodeGetAttributeExplicit = 0x200002f;
const int opcodeSetAttribute = 0x2000037; const int opcodeSetAttribute = 0x2000037;
@ -347,6 +349,13 @@ namespace Compiler
const int opcodeModSkill = 0x20000fa; const int opcodeModSkill = 0x20000fa;
const int opcodeModSkillExplicit = 0x2000115; const int opcodeModSkillExplicit = 0x2000115;
const int opcodeGetMagicEffect = 0x2000264;
const int opcodeGetMagicEffectExplicit = 0x200027c;
const int opcodeSetMagicEffect = 0x2000294;
const int opcodeSetMagicEffectExplicit = 0x20002ac;
const int opcodeModMagicEffect = 0x20002c4;
const int opcodeModMagicEffectExplicit = 0x20002dc;
const int opcodeGetPCCrimeLevel = 0x20001ec; const int opcodeGetPCCrimeLevel = 0x20001ec;
const int opcodeSetPCCrimeLevel = 0x20001ed; const int opcodeSetPCCrimeLevel = 0x20001ed;
const int opcodeModPCCrimeLevel = 0x20001ee; const int opcodeModPCCrimeLevel = 0x20001ee;

Loading…
Cancel
Save