diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 480c335c2a..ac8f85d134 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -461,6 +461,26 @@ namespace MWClass throw std::runtime_error(std::string("Unexpected soundgen type: ")+name); } + int Creature::getSkill(const MWWorld::Ptr &ptr, int skill) const + { + MWWorld::LiveCellRef *ref = + ptr.get(); + + const ESM::Skill* skillRecord = MWBase::Environment::get().getWorld()->getStore().get().find(skill); + + switch (skillRecord->mData.mSpecialization) + { + case ESM::Class::Combat: + return ref->mBase->mData.mCombat; + case ESM::Class::Magic: + return ref->mBase->mData.mMagic; + case ESM::Class::Stealth: + return ref->mBase->mData.mStealth; + default: + throw std::runtime_error("invalid specialisation"); + } + } + const ESM::GameSetting* Creature::fMinWalkSpeedCreature; const ESM::GameSetting* Creature::fMaxWalkSpeedCreature; } diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index 34e19ebdc7..461410a491 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -101,6 +101,8 @@ namespace MWClass } virtual bool isFlying (const MWWorld::Ptr &ptr) const; + + virtual int getSkill(const MWWorld::Ptr &ptr, int skill) const; }; } diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index c89822843c..8d51fd1cf9 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -1211,6 +1211,11 @@ namespace MWClass return MWWorld::Ptr(&cell.mNpcs.insert(*ref), &cell); } + int Npc::getSkill(const MWWorld::Ptr& ptr, int skill) const + { + return ptr.getClass().getNpcStats(ptr).getSkill(skill).getModified(); + } + const ESM::GameSetting *Npc::fMinWalkSpeed; const ESM::GameSetting *Npc::fMaxWalkSpeed; const ESM::GameSetting *Npc::fEncumberedMoveEffect; diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index 9977866cdf..b729d01514 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -140,6 +140,8 @@ namespace MWClass virtual std::string getModel(const MWWorld::Ptr &ptr) const; + virtual int getSkill(const MWWorld::Ptr& ptr, int skill) const; + virtual bool isActor() const { return true; } diff --git a/apps/openmw/mwgui/pickpocketitemmodel.cpp b/apps/openmw/mwgui/pickpocketitemmodel.cpp index 13ee4396d0..0196bf02d3 100644 --- a/apps/openmw/mwgui/pickpocketitemmodel.cpp +++ b/apps/openmw/mwgui/pickpocketitemmodel.cpp @@ -9,7 +9,7 @@ namespace MWGui PickpocketItemModel::PickpocketItemModel(const MWWorld::Ptr& thief, ItemModel *sourceModel) { mSourceModel = sourceModel; - int chance = MWWorld::Class::get(thief).getNpcStats(thief).getSkill(ESM::Skill::Sneak).getModified(); + int chance = thief.getClass().getSkill(thief, ESM::Skill::Sneak); mSourceModel->update(); for (size_t i = 0; igetItemCount(); ++i) diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 14024dec6b..f86044841a 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -296,10 +296,10 @@ namespace MWGui const MWMechanics::NpcStats &sellerStats = mPtr.getClass().getNpcStats(mPtr); const MWMechanics::NpcStats &playerStats = player.getClass().getNpcStats(player); - float a1 = std::min(playerStats.getSkill(ESM::Skill::Mercantile).getModified(), 100); + float a1 = std::min(player.getClass().getSkill(player, ESM::Skill::Mercantile), 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); + float d1 = std::min(mPtr.getClass().getSkill(mPtr, ESM::Skill::Mercantile), 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); diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 39c4219079..5104a0f57f 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1017,7 +1017,7 @@ void CharacterController::update(float duration) cls.getCreatureStats(mPtr).setHealth(health); cls.onHit(mPtr, realHealthLost, true, MWWorld::Ptr(), MWWorld::Ptr(), true); - const float acrobaticsSkill = cls.getNpcStats(mPtr).getSkill(ESM::Skill::Acrobatics).getModified(); + const float acrobaticsSkill = cls.getSkill(mPtr, ESM::Skill::Acrobatics); if (healthLost > (acrobaticsSkill * fatigueTerm)) { cls.getCreatureStats(mPtr).setKnockedDown(true); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 4514c077c7..0dee4706aa 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -902,12 +902,7 @@ namespace MWMechanics { static float fSneakSkillMult = store.find("fSneakSkillMult")->getFloat(); static float fSneakBootMult = store.find("fSneakBootMult")->getFloat(); - float sneak = 0; - // TODO: According to Hrnchamd Research:Movement, "Creatures have generalized combat, magic and stealth - // stats which substitute for the specific skills (in the same way as specializations)." - // This probably applies to a large part of the code base. - if (ptr.getClass().isNpc()) - sneak = ptr.getClass().getNpcStats(ptr).getSkill(ESM::Skill::Sneak).getModified(); + float sneak = ptr.getClass().getSkill(ptr, ESM::Skill::Sneak); int agility = stats.getAttribute(ESM::Attribute::Agility).getModified(); int luck = stats.getAttribute(ESM::Attribute::Luck).getModified(); float bootWeight = 0; @@ -935,9 +930,7 @@ namespace MWMechanics int obsAgility = observerStats.getAttribute(ESM::Attribute::Agility).getModified(); int obsLuck = observerStats.getAttribute(ESM::Attribute::Luck).getModified(); float obsBlind = observerStats.getMagicEffects().get(ESM::MagicEffect::Blind).mMagnitude; - int obsSneak = 0; - if (observer.getClass().isNpc()) - obsSneak = observer.getClass().getNpcStats(observer).getSkill(ESM::Skill::Sneak).getModified(); + int obsSneak = observer.getClass().getSkill(observer, ESM::Skill::Sneak); float obsTerm = obsSneak + 0.2 * obsAgility + 0.1 * obsLuck - obsBlind; diff --git a/apps/openmw/mwmechanics/pickpocket.cpp b/apps/openmw/mwmechanics/pickpocket.cpp index 8e8a70d885..53681caf8b 100644 --- a/apps/openmw/mwmechanics/pickpocket.cpp +++ b/apps/openmw/mwmechanics/pickpocket.cpp @@ -19,7 +19,7 @@ namespace MWMechanics NpcStats& stats = ptr.getClass().getNpcStats(ptr); float agility = stats.getAttribute(ESM::Attribute::Agility).getModified(); float luck = stats.getAttribute(ESM::Attribute::Luck).getModified(); - float sneak = stats.getSkill(ESM::Skill::Sneak).getModified(); + float sneak = ptr.getClass().getSkill(ptr, ESM::Skill::Sneak); return (add + 0.2 * agility + 0.1 * luck + sneak) * stats.getFatigueTerm(); } @@ -30,8 +30,7 @@ namespace MWMechanics float t = 2*x - y; - NpcStats& pcStats = mThief.getClass().getNpcStats(mThief); - float pcSneak = pcStats.getSkill(ESM::Skill::Sneak).getModified(); + float pcSneak = mThief.getClass().getSkill(mThief, ESM::Skill::Sneak); int iPickMinChance = MWBase::Environment::get().getWorld()->getStore().get() .find("iPickMinChance")->getInt(); int iPickMaxChance = MWBase::Environment::get().getWorld()->getStore().get() diff --git a/apps/openmw/mwmechanics/spellcasting.hpp b/apps/openmw/mwmechanics/spellcasting.hpp index a1ae254f61..52af26ad13 100644 --- a/apps/openmw/mwmechanics/spellcasting.hpp +++ b/apps/openmw/mwmechanics/spellcasting.hpp @@ -16,9 +16,9 @@ namespace MWMechanics { - inline int spellSchoolToSkill(int school) + inline ESM::Skill::SkillEnum spellSchoolToSkill(int school) { - std::map schoolSkillMap; // maps spell school to skill id + std::map schoolSkillMap; // maps spell school to skill id schoolSkillMap[0] = ESM::Skill::Alteration; schoolSkillMap[1] = ESM::Skill::Conjuration; schoolSkillMap[3] = ESM::Skill::Illusion; @@ -38,10 +38,9 @@ namespace MWMechanics */ inline float getSpellSuccessChance (const ESM::Spell* spell, const MWWorld::Ptr& actor, int* effectiveSchool = NULL) { - NpcStats& stats = MWWorld::Class::get(actor).getNpcStats(actor); - CreatureStats& creatureStats = MWWorld::Class::get(actor).getCreatureStats(actor); + CreatureStats& stats = actor.getClass().getCreatureStats(actor); - if (creatureStats.getMagicEffects().get(ESM::MagicEffect::Silence).mMagnitude) + if (stats.getMagicEffects().get(ESM::MagicEffect::Silence).mMagnitude) return 0; float y = FLT_MAX; @@ -63,7 +62,7 @@ namespace MWMechanics "fEffectCostMult")->getFloat(); x *= fEffectCostMult; - float s = 2 * stats.getSkill(spellSchoolToSkill(magicEffect->mData.mSchool)).getModified(); + float s = 2 * actor.getClass().getSkill(actor, spellSchoolToSkill(magicEffect->mData.mSchool)); if (s - x < y) { y = s - x; diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index 095fad7ab5..7a59e96893 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -306,9 +306,7 @@ namespace MWScript { MWWorld::Ptr ptr = R()(runtime); - Interpreter::Type_Integer value = - MWWorld::Class::get (ptr).getNpcStats (ptr).getSkill (mIndex). - getModified(); + Interpreter::Type_Integer value = ptr.getClass().getSkill(ptr, mIndex); runtime.push (value); } diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 07bd905717..f3128780b8 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -358,4 +358,9 @@ namespace MWWorld return false; } + int Class::getSkill(const MWWorld::Ptr& ptr, int skill) const + { + throw std::runtime_error("class does not support skills"); + } + } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 5c1c063a34..bbc74323cb 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -294,6 +294,8 @@ namespace MWWorld virtual bool isFlying(const MWWorld::Ptr& ptr) const; + virtual int getSkill(const MWWorld::Ptr& ptr, int skill) const; + static const Class& get (const std::string& key); ///< If there is no class for this \a key, an exception is thrown. diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index e8938b2c0e..82b827e755 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -164,8 +164,6 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::getSlot (int slot) void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor) { - const MWMechanics::NpcStats& stats = MWWorld::Class::get(actor).getNpcStats(actor); - TSlots slots_; initSlots (slots_); @@ -190,10 +188,10 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor) !actor.getRefData().getLocals().getIntVar(actor.getClass().getScript(actor), "companion"))) continue; - int testSkill = MWWorld::Class::get (test).getEquipmentSkill (test); + int testSkill = test.getClass().getEquipmentSkill (test); std::pair, bool> itemsSlots = - MWWorld::Class::get (*iter).getEquipmentSlots (*iter); + iter->getClass().getEquipmentSlots (*iter); for (std::vector::const_iterator iter2 (itemsSlots.first.begin()); iter2!=itemsSlots.first.end(); ++iter2) @@ -210,16 +208,16 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor) { // check skill int oldSkill = - MWWorld::Class::get (old).getEquipmentSkill (old); + old.getClass().getEquipmentSkill (old); if (testSkill!=-1 && oldSkill==-1) use = true; else if (testSkill!=-1 && oldSkill!=-1 && testSkill!=oldSkill) { - if (stats.getSkill (oldSkill).getModified()>stats.getSkill (testSkill).getModified()) + if (actor.getClass().getSkill(actor, oldSkill) > actor.getClass().getSkill (actor, testSkill)) continue; // rejected, because old item better matched the NPC's skills. - if (stats.getSkill (oldSkill).getModified()= - MWWorld::Class::get (test).getValue (test)) + if (old.getClass().getValue (old)>= + test.getClass().getValue (test)) { continue; } diff --git a/components/esm/loadcrea.hpp b/components/esm/loadcrea.hpp index b5ea495081..c0523025bd 100644 --- a/components/esm/loadcrea.hpp +++ b/components/esm/loadcrea.hpp @@ -63,7 +63,9 @@ struct Creature int mHealth, mMana, mFatigue; // Stats int mSoul; // The creatures soul value (used with soul gems.) - int mCombat, mMagic, mStealth; // Don't know yet. + // Creatures have generalized combat, magic and stealth stats which substitute for + // the specific skills (in the same way as specializations). + int mCombat, mMagic, mStealth; int mAttack[6]; // AttackMin1, AttackMax1, ditto2, ditto3 int mGold; }; // 96 byte