diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 471fda91c..f2e9c7492 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -357,6 +357,7 @@ namespace MWMechanics CreatureStats& creatureStats = creature.getClass().getCreatureStats (creature); if (creatureStats.isDead()) return; + MagicEffects now = creatureStats.getSpells().getMagicEffects(); if (creature.getTypeName()==typeid (ESM::NPC).name()) @@ -367,11 +368,7 @@ namespace MWMechanics now += creatureStats.getActiveSpells().getMagicEffects(); - //MagicEffects diff = MagicEffects::diff (creatureStats.getMagicEffects(), now); - - creatureStats.setMagicEffects(now); - - // TODO apply diff to other stats + creatureStats.modifyMagicEffects(now); } void Actors::calculateDynamicStats (const MWWorld::Ptr& ptr) @@ -1297,7 +1294,7 @@ namespace MWMechanics // Reset magic effects and recalculate derived effects // 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(); calculateCreatureStatModifiers(iter->first, 0); diff --git a/apps/openmw/mwmechanics/creaturestats.cpp b/apps/openmw/mwmechanics/creaturestats.cpp index 3981dacb9..324cad863 100644 --- a/apps/openmw/mwmechanics/creaturestats.cpp +++ b/apps/openmw/mwmechanics/creaturestats.cpp @@ -211,13 +211,13 @@ namespace MWMechanics mActiveSpells = active; } - void CreatureStats::setMagicEffects(const MagicEffects &effects) + void CreatureStats::modifyMagicEffects(const MagicEffects &effects) { - if (effects.get(ESM::MagicEffect::FortifyMaximumMagicka).getMagnitude() - != mMagicEffects.get(ESM::MagicEffect::FortifyMaximumMagicka).getMagnitude()) + if (effects.get(ESM::MagicEffect::FortifyMaximumMagicka).getModifier() + != mMagicEffects.get(ESM::MagicEffect::FortifyMaximumMagicka).getModifier()) mRecalcDynamicStats = true; - mMagicEffects = effects; + mMagicEffects.setModifiers(effects); } void CreatureStats::setAttackingOrSpell(bool attackingOrSpell) diff --git a/apps/openmw/mwmechanics/creaturestats.hpp b/apps/openmw/mwmechanics/creaturestats.hpp index a36d28fd3..037f37cc9 100644 --- a/apps/openmw/mwmechanics/creaturestats.hpp +++ b/apps/openmw/mwmechanics/creaturestats.hpp @@ -141,7 +141,8 @@ namespace MWMechanics 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); diff --git a/apps/openmw/mwmechanics/magiceffects.cpp b/apps/openmw/mwmechanics/magiceffects.cpp index 77a198f50..12fc78e1e 100644 --- a/apps/openmw/mwmechanics/magiceffects.cpp +++ b/apps/openmw/mwmechanics/magiceffects.cpp @@ -42,23 +42,45 @@ namespace MWMechanics 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) { - mMagnitude += param.mMagnitude; + mModifier += param.mModifier; + mBase += param.mBase; return *this; } EffectParam& EffectParam::operator-= (const EffectParam& param) { - mMagnitude -= param.mMagnitude; + mModifier -= param.mModifier; + mBase -= param.mBase; return *this; } + void MagicEffects::remove(const EffectKey &key) + { + mCollection.erase(key); + } + void MagicEffects::add (const EffectKey& key, const EffectParam& param) { 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) { if (this==&effects) diff --git a/apps/openmw/mwmechanics/magiceffects.hpp b/apps/openmw/mwmechanics/magiceffects.hpp index 75a360cbe..9833c531f 100644 --- a/apps/openmw/mwmechanics/magiceffects.hpp +++ b/apps/openmw/mwmechanics/magiceffects.hpp @@ -30,15 +30,23 @@ namespace MWMechanics { private: // Note usually this would be int, but applying partial resistance might introduce a decimal point. - float mMagnitude; + float mModifier; + + int mBase; public: /// Get the total magnitude including base and modifier. float getMagnitude() const; + void setModifier(float mod); + float getModifier() const; + + /// Change mBase by \a diff + void modifyBase(int diff); + EffectParam(); - EffectParam(float magnitude) : mMagnitude(magnitude) {} + EffectParam(float magnitude) : mModifier(magnitude), mBase(0) {} EffectParam& operator+= (const EffectParam& param); @@ -83,6 +91,12 @@ namespace MWMechanics Collection::const_iterator end() const { return mCollection.end(); } 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); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 8ca322c20..d0f11b892 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -68,7 +68,7 @@ namespace MWMechanics // reset creatureStats.setLevel(player->mNpdt52.mLevel); creatureStats.getSpells().clear(); - creatureStats.setMagicEffects(MagicEffects()); + creatureStats.modifyMagicEffects(MagicEffects()); for (int i=0; i<27; ++i) npcStats.getSkill (i).setBase (player->mNpdt52.mSkills[i]); diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index f600117a9..7397355e3 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -421,5 +421,15 @@ op 0x200025c: ClearForceMoveJump op 0x200025d: ClearForceMoveJump, explicit reference op 0x200025e: ForceMoveJump 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 diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index 7150704ca..49a483f27 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -1176,6 +1176,91 @@ namespace MWScript } }; + template + 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(currentValue); + runtime.push(ret); + } + }; + + template + 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 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) { for (int i=0; i); interpreter.installSegment5 (Compiler::Stats::opcodeGetStat, new OpGetStat); interpreter.installSegment5 (Compiler::Stats::opcodeGetStatExplicit, new OpGetStat); + + 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 (positive, negative)); + interpreter.installSegment5 (Compiler::Stats::opcodeGetMagicEffectExplicit+i, new OpGetMagicEffect (positive, negative)); + + interpreter.installSegment5 (Compiler::Stats::opcodeSetMagicEffect+i, new OpSetMagicEffect (positive, negative)); + interpreter.installSegment5 (Compiler::Stats::opcodeSetMagicEffectExplicit+i, new OpSetMagicEffect (positive, negative)); + + interpreter.installSegment5 (Compiler::Stats::opcodeModMagicEffect+i, new OpModMagicEffect (positive, negative)); + interpreter.installSegment5 (Compiler::Stats::opcodeModMagicEffectExplicit+i, new OpModMagicEffect (positive, negative)); + } } } } diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index b01783e04..dcbe707b7 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -640,7 +640,7 @@ void MWWorld::InventoryStore::rechargeItems(float duration) 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() diff --git a/components/compiler/extensions0.cpp b/components/compiler/extensions0.cpp index 73877f459..a2dc97a1a 100644 --- a/components/compiler/extensions0.cpp +++ b/components/compiler/extensions0.cpp @@ -370,6 +370,16 @@ namespace Compiler "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 set ("set"); std::string mod ("mod"); @@ -418,6 +428,18 @@ namespace Compiler opcodeModSkill+i, opcodeModSkillExplicit+i); } + for (int i=0; i