mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-02-21 09:39:56 +00:00
Use RefId key for NPC skills
This commit is contained in:
parent
1b956521fc
commit
47c1569961
@ -298,7 +298,7 @@ namespace MWClass
|
||||
const MWWorld::LiveCellRef<ESM::Armor>* ref = ptr.get<ESM::Armor>();
|
||||
|
||||
int armorSkillType = getEquipmentSkill(ptr);
|
||||
float armorSkill = actor.getClass().getSkill(actor, armorSkillType);
|
||||
float armorSkill = actor.getClass().getSkill(actor, ESM::Skill::indexToRefId(armorSkillType));
|
||||
|
||||
int iBaseArmorSkill = MWBase::Environment::get()
|
||||
.getESMStore()
|
||||
|
@ -762,11 +762,11 @@ namespace MWClass
|
||||
throw std::runtime_error("Unexpected soundgen type: " + std::string(name));
|
||||
}
|
||||
|
||||
float Creature::getSkill(const MWWorld::Ptr& ptr, int skill) const
|
||||
float Creature::getSkill(const MWWorld::Ptr& ptr, ESM::RefId id) const
|
||||
{
|
||||
MWWorld::LiveCellRef<ESM::Creature>* ref = ptr.get<ESM::Creature>();
|
||||
|
||||
const ESM::Skill* skillRecord = MWBase::Environment::get().getESMStore()->get<ESM::Skill>().find(skill);
|
||||
const ESM::Skill* skillRecord = MWBase::Environment::get().getESMStore()->get<ESM::Skill>().find(id);
|
||||
|
||||
switch (skillRecord->mData.mSpecialization)
|
||||
{
|
||||
|
@ -115,7 +115,7 @@ namespace MWClass
|
||||
bool canSwim(const MWWorld::ConstPtr& ptr) const override;
|
||||
bool canWalk(const MWWorld::ConstPtr& ptr) const override;
|
||||
|
||||
float getSkill(const MWWorld::Ptr& ptr, int skill) const override;
|
||||
float getSkill(const MWWorld::Ptr& ptr, ESM::RefId id) const override;
|
||||
|
||||
/// Get a blood texture suitable for \a ptr (see Blood Texture 0-2 in Morrowind.ini)
|
||||
int getBloodTexture(const MWWorld::ConstPtr& ptr) const override;
|
||||
|
@ -181,10 +181,10 @@ namespace
|
||||
|
||||
for (const auto& skills : class_->mData.mSkills)
|
||||
{
|
||||
int index = skills[i];
|
||||
if (index >= 0 && index < ESM::Skill::Length)
|
||||
ESM::RefId id = ESM::Skill::indexToRefId(skills[i]);
|
||||
if (!id.empty())
|
||||
{
|
||||
npcStats.getSkill(index).setBase(npcStats.getSkill(index).getBase() + bonus);
|
||||
npcStats.getSkill(id).setBase(npcStats.getSkill(id).getBase() + bonus);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -220,23 +220,19 @@ namespace
|
||||
specBonus = 5;
|
||||
}
|
||||
|
||||
npcStats.getSkill(skillIndex)
|
||||
.setBase(std::min(round_ieee_754(npcStats.getSkill(skillIndex).getBase() + 5 + raceBonus + specBonus
|
||||
npcStats.getSkill(skill->mId)
|
||||
.setBase(std::min(round_ieee_754(npcStats.getSkill(skill->mId).getBase() + 5 + raceBonus + specBonus
|
||||
+ (int(level) - 1) * (majorMultiplier + specMultiplier)),
|
||||
100)); // Must gracefully handle level 0
|
||||
}
|
||||
|
||||
int skills[ESM::Skill::Length];
|
||||
for (int i = 0; i < ESM::Skill::Length; ++i)
|
||||
skills[i] = npcStats.getSkill(i).getBase();
|
||||
|
||||
int attributes[ESM::Attribute::Length];
|
||||
for (int i = 0; i < ESM::Attribute::Length; ++i)
|
||||
attributes[i] = npcStats.getAttribute(i).getBase();
|
||||
|
||||
if (!spellsInitialised)
|
||||
{
|
||||
std::vector<ESM::RefId> spells = MWMechanics::autoCalcNpcSpells(skills, attributes, race);
|
||||
std::vector<ESM::RefId> spells = MWMechanics::autoCalcNpcSpells(npcStats.getSkills(), attributes, race);
|
||||
npcStats.getSpells().addAllToInstance(spells);
|
||||
}
|
||||
}
|
||||
@ -315,7 +311,7 @@ namespace MWClass
|
||||
gold = ref->mBase->mNpdt.mGold;
|
||||
|
||||
for (size_t i = 0; i < ref->mBase->mNpdt.mSkills.size(); ++i)
|
||||
data->mNpcStats.getSkill(i).setBase(ref->mBase->mNpdt.mSkills[i]);
|
||||
data->mNpcStats.getSkill(ESM::Skill::indexToRefId(i)).setBase(ref->mBase->mNpdt.mSkills[i]);
|
||||
|
||||
data->mNpcStats.setAttribute(ESM::Attribute::Strength, ref->mBase->mNpdt.mStrength);
|
||||
data->mNpcStats.setAttribute(ESM::Attribute::Intelligence, ref->mBase->mNpdt.mIntelligence);
|
||||
@ -593,7 +589,7 @@ namespace MWClass
|
||||
if (!weapon.isEmpty())
|
||||
weapskill = weapon.getClass().getEquipmentSkill(weapon);
|
||||
|
||||
float hitchance = MWMechanics::getHitChance(ptr, victim, getSkill(ptr, weapskill));
|
||||
float hitchance = MWMechanics::getHitChance(ptr, victim, getSkill(ptr, ESM::Skill::indexToRefId(weapskill)));
|
||||
|
||||
return Misc::Rng::roll0to99(world->getPrng()) < hitchance;
|
||||
}
|
||||
@ -1052,7 +1048,7 @@ namespace MWClass
|
||||
const float encumbranceTerm = gmst.fJumpEncumbranceBase->mValue.getFloat()
|
||||
+ gmst.fJumpEncumbranceMultiplier->mValue.getFloat() * (1.0f - Npc::getNormalizedEncumbrance(ptr));
|
||||
|
||||
float a = getSkill(ptr, ESM::Skill::Acrobatics);
|
||||
float a = Class::getSkill(ptr, ESM::Skill::Acrobatics);
|
||||
float b = 0.0f;
|
||||
if (a > 50.0f)
|
||||
{
|
||||
@ -1185,7 +1181,7 @@ namespace MWClass
|
||||
|
||||
float fUnarmoredBase1 = store.find("fUnarmoredBase1")->mValue.getFloat();
|
||||
float fUnarmoredBase2 = store.find("fUnarmoredBase2")->mValue.getFloat();
|
||||
float unarmoredSkill = getSkill(ptr, ESM::Skill::Unarmored);
|
||||
float unarmoredSkill = Class::getSkill(ptr, ESM::Skill::Unarmored);
|
||||
|
||||
float ratings[MWWorld::InventoryStore::Slots];
|
||||
for (int i = 0; i < MWWorld::InventoryStore::Slots; i++)
|
||||
@ -1355,9 +1351,9 @@ namespace MWClass
|
||||
return MWWorld::Ptr(cell.insert(ref), &cell);
|
||||
}
|
||||
|
||||
float Npc::getSkill(const MWWorld::Ptr& ptr, int skill) const
|
||||
float Npc::getSkill(const MWWorld::Ptr& ptr, ESM::RefId id) const
|
||||
{
|
||||
return getNpcStats(ptr).getSkill(skill).getModified();
|
||||
return getNpcStats(ptr).getSkill(id).getModified();
|
||||
}
|
||||
|
||||
int Npc::getBloodTexture(const MWWorld::ConstPtr& ptr) const
|
||||
@ -1550,7 +1546,7 @@ namespace MWClass
|
||||
{
|
||||
const GMST& gmst = getGmst();
|
||||
return getWalkSpeed(ptr)
|
||||
* (0.01f * getSkill(ptr, ESM::Skill::Athletics) * gmst.fAthleticsRunBonus->mValue.getFloat()
|
||||
* (0.01f * Class::getSkill(ptr, ESM::Skill::Athletics) * gmst.fAthleticsRunBonus->mValue.getFloat()
|
||||
+ gmst.fBaseRunMultiplier->mValue.getFloat());
|
||||
}
|
||||
|
||||
|
@ -134,7 +134,7 @@ namespace MWClass
|
||||
|
||||
std::string getModel(const MWWorld::ConstPtr& ptr) const override;
|
||||
|
||||
float getSkill(const MWWorld::Ptr& ptr, int skill) const override;
|
||||
float getSkill(const MWWorld::Ptr& ptr, ESM::RefId id) const override;
|
||||
|
||||
/// Get a blood texture suitable for \a ptr (see Blood Texture 0-2 in Morrowind.ini)
|
||||
int getBloodTexture(const MWWorld::ConstPtr& ptr) const override;
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include <components/esm3/loadcrea.hpp>
|
||||
#include <components/esm3/loadfact.hpp>
|
||||
#include <components/esm3/loadmgef.hpp>
|
||||
#include <components/esm3/loadskil.hpp>
|
||||
|
||||
#include "../mwbase/dialoguemanager.hpp"
|
||||
#include "../mwbase/environment.hpp"
|
||||
@ -385,9 +386,10 @@ int MWDialogue::Filter::getSelectStructInteger(const SelectWrapper& select) cons
|
||||
return player.getClass().getCreatureStats(player).getAttribute(select.getArgument()).getModified();
|
||||
|
||||
case SelectWrapper::Function_PcSkill:
|
||||
|
||||
return static_cast<int>(player.getClass().getNpcStats(player).getSkill(select.getArgument()).getModified());
|
||||
|
||||
{
|
||||
ESM::RefId skill = ESM::Skill::indexToRefId(select.getArgument());
|
||||
return static_cast<int>(player.getClass().getNpcStats(player).getSkill(skill).getModified());
|
||||
}
|
||||
case SelectWrapper::Function_FriendlyHit:
|
||||
{
|
||||
int hits = mActor.getClass().getCreatureStats(mActor).getFriendlyHits();
|
||||
|
@ -96,7 +96,7 @@ namespace MWGui
|
||||
const ESM::Skill* skill = skillStore.searchRandom({}, prng);
|
||||
skills.insert(skill);
|
||||
|
||||
MWMechanics::SkillValue& value = player.getClass().getNpcStats(player).getSkill(skill->mIndex);
|
||||
MWMechanics::SkillValue& value = player.getClass().getNpcStats(player).getSkill(skill->mId);
|
||||
if (skill->mIndex == ESM::Skill::Security || skill->mIndex == ESM::Skill::Sneak)
|
||||
value.setBase(std::min(100.f, value.getBase() + 1));
|
||||
else
|
||||
@ -116,7 +116,7 @@ namespace MWGui
|
||||
|
||||
for (const ESM::Skill* skill : skills)
|
||||
{
|
||||
int skillValue = player.getClass().getNpcStats(player).getSkill(skill->mIndex).getBase();
|
||||
int skillValue = player.getClass().getNpcStats(player).getSkill(skill->mId).getBase();
|
||||
std::string skillMsg = gmst.find("sNotifyMessage44")->mValue.getString();
|
||||
if (skill->mIndex == ESM::Skill::Sneak || skill->mIndex == ESM::Skill::Security)
|
||||
skillMsg = gmst.find("sNotifyMessage39")->mValue.getString();
|
||||
|
@ -90,10 +90,10 @@ namespace MWGui
|
||||
getWidget(mSkillView, "SkillView");
|
||||
mSkillView->eventMouseWheel += MyGUI::newDelegate(this, &ReviewDialog::onMouseWheel);
|
||||
|
||||
for (int i = 0; i < ESM::Skill::Length; ++i)
|
||||
for (const ESM::Skill& skill : MWBase::Environment::get().getESMStore()->get<ESM::Skill>())
|
||||
{
|
||||
mSkillValues.insert(std::make_pair(i, MWMechanics::SkillValue()));
|
||||
mSkillWidgetMap.insert(std::make_pair(i, static_cast<MyGUI::TextBox*>(nullptr)));
|
||||
mSkillValues.emplace(skill.mId, MWMechanics::SkillValue());
|
||||
mSkillWidgetMap.emplace(skill.mIndex, static_cast<MyGUI::TextBox*>(nullptr));
|
||||
}
|
||||
|
||||
MyGUI::Button* backButton;
|
||||
@ -206,11 +206,12 @@ namespace MWGui
|
||||
|
||||
void ReviewDialog::setSkillValue(ESM::Skill::SkillEnum skillId, const MWMechanics::SkillValue& value)
|
||||
{
|
||||
mSkillValues[skillId] = value;
|
||||
mSkillValues[ESM::Skill::indexToRefId(skillId)] = value;
|
||||
MyGUI::TextBox* widget = mSkillWidgetMap[skillId];
|
||||
if (widget)
|
||||
{
|
||||
float modified = static_cast<float>(value.getModified()), base = static_cast<float>(value.getBase());
|
||||
float modified = value.getModified();
|
||||
float base = value.getBase();
|
||||
std::string text = MyGUI::utility::toString(std::floor(modified));
|
||||
std::string state = "normal";
|
||||
if (modified > base)
|
||||
@ -345,7 +346,7 @@ namespace MWGui
|
||||
ESM::Skill::indexToRefId(skillIndex));
|
||||
if (!skill) // Skip unknown skills
|
||||
continue;
|
||||
const MWMechanics::SkillValue& stat = mSkillValues.find(skill->mIndex)->second;
|
||||
const MWMechanics::SkillValue& stat = mSkillValues.find(skill->mId)->second;
|
||||
int base = stat.getBase();
|
||||
int modified = stat.getModified();
|
||||
|
||||
@ -394,15 +395,11 @@ namespace MWGui
|
||||
if (!mRaceId.empty())
|
||||
race = MWBase::Environment::get().getESMStore()->get<ESM::Race>().find(mRaceId);
|
||||
|
||||
int skills[ESM::Skill::Length];
|
||||
for (int i = 0; i < ESM::Skill::Length; ++i)
|
||||
skills[i] = mSkillValues.find(i)->second.getBase();
|
||||
|
||||
int attributes[ESM::Attribute::Length];
|
||||
for (int i = 0; i < ESM::Attribute::Length; ++i)
|
||||
attributes[i] = mAttributeWidgets[i]->getAttributeValue().getBase();
|
||||
|
||||
std::vector<ESM::RefId> selectedSpells = MWMechanics::autoCalcPlayerSpells(skills, attributes, race);
|
||||
std::vector<ESM::RefId> selectedSpells = MWMechanics::autoCalcPlayerSpells(mSkillValues, attributes, race);
|
||||
for (ESM::RefId& spellId : selectedSpells)
|
||||
{
|
||||
if (std::find(spells.begin(), spells.end(), spellId) == spells.end())
|
||||
|
@ -94,7 +94,7 @@ namespace MWGui
|
||||
std::map<int, Widgets::MWAttributePtr> mAttributeWidgets;
|
||||
|
||||
SkillList mMajorSkills, mMinorSkills, mMiscSkills;
|
||||
std::map<int, MWMechanics::SkillValue> mSkillValues;
|
||||
std::map<ESM::RefId, MWMechanics::SkillValue> mSkillValues;
|
||||
std::map<int, MyGUI::TextBox*> mSkillWidgetMap;
|
||||
ESM::RefId mRaceId, mBirthSignId;
|
||||
std::string mName;
|
||||
|
@ -83,13 +83,13 @@ namespace MWGui
|
||||
}
|
||||
}
|
||||
|
||||
// Loop over ESM::Skill::SkillEnum
|
||||
for (int i = 0; i < ESM::Skill::Length; ++i)
|
||||
for (const ESM::Skill& skill : MWBase::Environment::get().getESMStore()->get<ESM::Skill>())
|
||||
{
|
||||
if (stats.getSkill(i) != mWatchedSkills[i] || mWatchedStatsEmpty)
|
||||
const auto& value = stats.getSkill(skill.mId);
|
||||
if (value != mWatchedSkills[skill.mIndex] || mWatchedStatsEmpty)
|
||||
{
|
||||
mWatchedSkills[i] = stats.getSkill(i);
|
||||
setValue((ESM::Skill::SkillEnum)i, stats.getSkill(i));
|
||||
mWatchedSkills[skill.mIndex] = value;
|
||||
setValue(ESM::Skill::SkillEnum(skill.mIndex), value);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -237,7 +237,7 @@ namespace MWGui
|
||||
}
|
||||
}
|
||||
|
||||
void setSkillProgress(MyGUI::Widget* w, float progress, int skillId)
|
||||
void setSkillProgress(MyGUI::Widget* w, float progress, ESM::RefId skillId)
|
||||
{
|
||||
MWWorld::Ptr player = MWMechanics::getPlayer();
|
||||
const MWWorld::ESMStore& esmStore = *MWBase::Environment::get().getESMStore();
|
||||
@ -296,8 +296,9 @@ namespace MWGui
|
||||
valueWidget->setUserString("Visible_SkillProgressVBox", "true");
|
||||
valueWidget->setUserString("UserData^Hidden_SkillProgressVBox", "false");
|
||||
|
||||
setSkillProgress(nameWidget, value.getProgress(), parSkill);
|
||||
setSkillProgress(valueWidget, value.getProgress(), parSkill);
|
||||
ESM::RefId id = ESM::Skill::indexToRefId(parSkill);
|
||||
setSkillProgress(nameWidget, value.getProgress(), id);
|
||||
setSkillProgress(valueWidget, value.getProgress(), id);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -72,7 +72,7 @@ namespace MWGui
|
||||
MWMechanics::NpcStats const& actorStats(actor.getClass().getNpcStats(actor));
|
||||
for (const ESM::Skill& skill : skillStore)
|
||||
{
|
||||
float value = getSkillForTraining(actorStats, skill.mIndex);
|
||||
float value = getSkillForTraining(actorStats, skill.mId);
|
||||
|
||||
skills.emplace_back(&skill, value);
|
||||
}
|
||||
@ -92,7 +92,7 @@ namespace MWGui
|
||||
{
|
||||
const ESM::Skill* skill = skills[i].first;
|
||||
int price = static_cast<int>(
|
||||
pcStats.getSkill(skill->mIndex).getBase() * gmst.find("iTrainingMod")->mValue.getInteger());
|
||||
pcStats.getSkill(skill->mId).getBase() * gmst.find("iTrainingMod")->mValue.getInteger());
|
||||
price = std::max(1, price);
|
||||
price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr, price, true);
|
||||
|
||||
@ -135,22 +135,22 @@ namespace MWGui
|
||||
|
||||
const MWWorld::ESMStore& store = *MWBase::Environment::get().getESMStore();
|
||||
|
||||
int price = pcStats.getSkill(skill->mIndex).getBase()
|
||||
int price = pcStats.getSkill(skill->mId).getBase()
|
||||
* store.get<ESM::GameSetting>().find("iTrainingMod")->mValue.getInteger();
|
||||
price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr, price, true);
|
||||
|
||||
if (price > player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId))
|
||||
return;
|
||||
|
||||
if (getSkillForTraining(mPtr.getClass().getNpcStats(mPtr), skill->mIndex)
|
||||
<= pcStats.getSkill(skill->mIndex).getBase())
|
||||
if (getSkillForTraining(mPtr.getClass().getNpcStats(mPtr), skill->mId)
|
||||
<= pcStats.getSkill(skill->mId).getBase())
|
||||
{
|
||||
MWBase::Environment::get().getWindowManager()->messageBox("#{sServiceTrainingWords}");
|
||||
return;
|
||||
}
|
||||
|
||||
// You can not train a skill above its governing attribute
|
||||
if (pcStats.getSkill(skill->mIndex).getBase() >= pcStats.getAttribute(skill->mData.mAttribute).getBase())
|
||||
if (pcStats.getSkill(skill->mId).getBase() >= pcStats.getAttribute(skill->mData.mAttribute).getBase())
|
||||
{
|
||||
MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage17}");
|
||||
return;
|
||||
@ -196,11 +196,11 @@ namespace MWGui
|
||||
MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode();
|
||||
}
|
||||
|
||||
float TrainingWindow::getSkillForTraining(const MWMechanics::NpcStats& stats, int skillId) const
|
||||
float TrainingWindow::getSkillForTraining(const MWMechanics::NpcStats& stats, ESM::RefId id) const
|
||||
{
|
||||
if (mTrainingSkillBasedOnBaseSkill)
|
||||
return stats.getSkill(skillId).getBase();
|
||||
return stats.getSkill(skillId).getModified();
|
||||
return stats.getSkill(id).getBase();
|
||||
return stats.getSkill(id).getModified();
|
||||
}
|
||||
|
||||
void TrainingWindow::onFrame(float dt)
|
||||
|
@ -42,7 +42,7 @@ namespace MWGui
|
||||
|
||||
// Retrieve the base skill value if the setting 'training skills based on base skill' is set;
|
||||
// otherwise returns the modified skill
|
||||
float getSkillForTraining(const MWMechanics::NpcStats& stats, int skillId) const;
|
||||
float getSkillForTraining(const MWMechanics::NpcStats& stats, ESM::RefId id) const;
|
||||
|
||||
MyGUI::Widget* mTrainingOptions;
|
||||
MyGUI::Button* mCancelButton;
|
||||
|
@ -25,8 +25,8 @@ namespace
|
||||
using SelfObject = MWLua::SelfObject;
|
||||
using ObjectVariant = MWLua::ObjectVariant;
|
||||
|
||||
template <class T>
|
||||
auto addIndexedAccessor(int index)
|
||||
template <class T, class I>
|
||||
auto addIndexedAccessor(I index)
|
||||
{
|
||||
return [index](const sol::object& o) { return T::create(ObjectVariant(o), index); };
|
||||
}
|
||||
@ -228,37 +228,36 @@ namespace MWLua
|
||||
class SkillStat
|
||||
{
|
||||
ObjectVariant mObject;
|
||||
int mIndex;
|
||||
ESM::RefId mId;
|
||||
|
||||
SkillStat(ObjectVariant object, int index)
|
||||
SkillStat(ObjectVariant object, ESM::RefId id)
|
||||
: mObject(std::move(object))
|
||||
, mIndex(index)
|
||||
, mId(id)
|
||||
{
|
||||
}
|
||||
|
||||
static float getProgress(const MWWorld::Ptr& ptr, int index, const MWMechanics::SkillValue& stat)
|
||||
static float getProgress(const MWWorld::Ptr& ptr, ESM::RefId id, const MWMechanics::SkillValue& stat)
|
||||
{
|
||||
float progress = stat.getProgress();
|
||||
if (progress != 0.f)
|
||||
progress /= getMaxProgress(ptr, index, stat);
|
||||
progress /= getMaxProgress(ptr, id, stat);
|
||||
return progress;
|
||||
}
|
||||
|
||||
static float getMaxProgress(const MWWorld::Ptr& ptr, int index, const MWMechanics::SkillValue& stat)
|
||||
static float getMaxProgress(const MWWorld::Ptr& ptr, ESM::RefId id, const MWMechanics::SkillValue& stat)
|
||||
{
|
||||
const auto& store = *MWBase::Environment::get().getESMStore();
|
||||
const auto cl = store.get<ESM::Class>().find(ptr.get<ESM::NPC>()->mBase->mClass);
|
||||
return ptr.getClass().getNpcStats(ptr).getSkillProgressRequirement(index, *cl);
|
||||
return ptr.getClass().getNpcStats(ptr).getSkillProgressRequirement(id, *cl);
|
||||
}
|
||||
|
||||
public:
|
||||
template <class G>
|
||||
sol::object get(const Context& context, std::string_view prop, G getter) const
|
||||
{
|
||||
return getValue(
|
||||
context, mObject, &SkillStat::setValue, mIndex, prop, [this, getter](const MWWorld::Ptr& ptr) {
|
||||
return (ptr.getClass().getNpcStats(ptr).getSkill(mIndex).*getter)();
|
||||
});
|
||||
return getValue(context, mObject, &SkillStat::setValue, mId.getIf<ESM::IndexRefId>()->getValue(), prop,
|
||||
[this, getter](
|
||||
const MWWorld::Ptr& ptr) { return (ptr.getClass().getNpcStats(ptr).getSkill(mId).*getter)(); });
|
||||
}
|
||||
|
||||
float getModified(const Context& context) const
|
||||
@ -271,30 +270,33 @@ namespace MWLua
|
||||
|
||||
sol::object getProgress(const Context& context) const
|
||||
{
|
||||
return getValue(
|
||||
context, mObject, &SkillStat::setValue, mIndex, "progress", [this](const MWWorld::Ptr& ptr) {
|
||||
return getProgress(ptr, mIndex, ptr.getClass().getNpcStats(ptr).getSkill(mIndex));
|
||||
return getValue(context, mObject, &SkillStat::setValue, mId.getIf<ESM::IndexRefId>()->getValue(),
|
||||
"progress", [this](const MWWorld::Ptr& ptr) {
|
||||
return getProgress(ptr, mId, ptr.getClass().getNpcStats(ptr).getSkill(mId));
|
||||
});
|
||||
}
|
||||
|
||||
static std::optional<SkillStat> create(ObjectVariant object, int index)
|
||||
static std::optional<SkillStat> create(ObjectVariant object, ESM::RefId id)
|
||||
{
|
||||
if (!object.ptr().getClass().isNpc())
|
||||
return {};
|
||||
return SkillStat{ std::move(object), index };
|
||||
return SkillStat{ std::move(object), id };
|
||||
}
|
||||
|
||||
void cache(const Context& context, std::string_view prop, const sol::object& value) const
|
||||
{
|
||||
SelfObject* obj = mObject.asSelfObject();
|
||||
addStatUpdateAction(context.mLuaManager, *obj);
|
||||
obj->mStatsCache[SelfObject::CachedStat{ &SkillStat::setValue, mIndex, prop }] = value;
|
||||
obj->mStatsCache[SelfObject::CachedStat{
|
||||
&SkillStat::setValue, int(mId.getIf<ESM::IndexRefId>()->getValue()), prop }]
|
||||
= value;
|
||||
}
|
||||
|
||||
static void setValue(int index, std::string_view prop, const MWWorld::Ptr& ptr, const sol::object& value)
|
||||
{
|
||||
ESM::RefId id = ESM::Skill::indexToRefId(index);
|
||||
auto& stats = ptr.getClass().getNpcStats(ptr);
|
||||
auto stat = stats.getSkill(index);
|
||||
auto stat = stats.getSkill(id);
|
||||
float floatValue = LuaUtil::cast<float>(value);
|
||||
if (prop == "base")
|
||||
stat.setBase(floatValue);
|
||||
@ -306,8 +308,8 @@ namespace MWLua
|
||||
else if (prop == "modifier")
|
||||
stat.setModifier(floatValue);
|
||||
else if (prop == "progress")
|
||||
stat.setProgress(floatValue * getMaxProgress(ptr, index, stat));
|
||||
stats.setSkill(index, stat);
|
||||
stat.setProgress(floatValue * getMaxProgress(ptr, id, stat));
|
||||
stats.setSkill(id, stat);
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -385,7 +387,8 @@ namespace MWLua
|
||||
[context](const SkillStat& stat, const sol::object& value) { stat.cache(context, "progress", value); });
|
||||
sol::table skills(context.mLua->sol(), sol::create);
|
||||
npcStats["skills"] = LuaUtil::makeReadOnly(skills);
|
||||
for (int id = ESM::Skill::Block; id < ESM::Skill::Length; ++id)
|
||||
skills[Misc::StringUtils::lowerCase(ESM::Skill::sSkillNames[id])] = addIndexedAccessor<SkillStat>(id);
|
||||
for (const ESM::Skill& skill : MWBase::Environment::get().getESMStore()->get<ESM::Skill>())
|
||||
skills[Misc::StringUtils::lowerCase(ESM::Skill::sSkillNames[skill.mIndex])]
|
||||
= addIndexedAccessor<SkillStat>(skill.mId);
|
||||
}
|
||||
}
|
||||
|
@ -27,7 +27,8 @@ namespace MWMechanics
|
||||
ESM::RefId mWeakestSpell;
|
||||
};
|
||||
|
||||
std::vector<ESM::RefId> autoCalcNpcSpells(const int* actorSkills, const int* actorAttributes, const ESM::Race* race)
|
||||
std::vector<ESM::RefId> autoCalcNpcSpells(
|
||||
const std::map<ESM::RefId, SkillValue>& actorSkills, const int* actorAttributes, const ESM::Race* race)
|
||||
{
|
||||
const MWWorld::Store<ESM::GameSetting>& gmst
|
||||
= MWBase::Environment::get().getESMStore()->get<ESM::GameSetting>();
|
||||
@ -148,7 +149,7 @@ namespace MWMechanics
|
||||
}
|
||||
|
||||
std::vector<ESM::RefId> autoCalcPlayerSpells(
|
||||
const int* actorSkills, const int* actorAttributes, const ESM::Race* race)
|
||||
const std::map<ESM::RefId, SkillValue>& actorSkills, const int* actorAttributes, const ESM::Race* race)
|
||||
{
|
||||
const MWWorld::ESMStore& esmStore = *MWBase::Environment::get().getESMStore();
|
||||
|
||||
@ -226,7 +227,8 @@ namespace MWMechanics
|
||||
return selectedSpells;
|
||||
}
|
||||
|
||||
bool attrSkillCheck(const ESM::Spell* spell, const int* actorSkills, const int* actorAttributes)
|
||||
bool attrSkillCheck(
|
||||
const ESM::Spell* spell, const std::map<ESM::RefId, SkillValue>& actorSkills, const int* actorAttributes)
|
||||
{
|
||||
for (const auto& spellEffect : spell->mEffects.mList)
|
||||
{
|
||||
@ -240,8 +242,9 @@ namespace MWMechanics
|
||||
|
||||
if ((magicEffect->mData.mFlags & ESM::MagicEffect::TargetSkill))
|
||||
{
|
||||
assert(spellEffect.mSkill >= 0 && spellEffect.mSkill < ESM::Skill::Length);
|
||||
if (actorSkills[spellEffect.mSkill] < iAutoSpellAttSkillMin)
|
||||
ESM::RefId skill = ESM::Skill::indexToRefId(spellEffect.mSkill);
|
||||
auto found = actorSkills.find(skill);
|
||||
if (found == actorSkills.end() || found->second.getBase() < iAutoSpellAttSkillMin)
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -256,7 +259,8 @@ namespace MWMechanics
|
||||
return true;
|
||||
}
|
||||
|
||||
void calcWeakestSchool(const ESM::Spell* spell, const int* actorSkills, int& effectiveSchool, float& skillTerm)
|
||||
void calcWeakestSchool(const ESM::Spell* spell, const std::map<ESM::RefId, SkillValue>& actorSkills,
|
||||
int& effectiveSchool, float& skillTerm)
|
||||
{
|
||||
// Morrowind for some reason uses a formula slightly different from magicka cost calculation
|
||||
float minChance = std::numeric_limits<float>::max();
|
||||
@ -294,7 +298,11 @@ namespace MWMechanics
|
||||
if (effect.mRange == ESM::RT_Target)
|
||||
x *= 1.5f;
|
||||
|
||||
float s = 2.f * actorSkills[spellSchoolToSkill(magicEffect->mData.mSchool)];
|
||||
float s = 0.f;
|
||||
ESM::RefId skill = ESM::Skill::indexToRefId(spellSchoolToSkill(magicEffect->mData.mSchool));
|
||||
auto found = actorSkills.find(skill);
|
||||
if (found != actorSkills.end())
|
||||
s = 2.f * found->second.getBase();
|
||||
if (s - x < minChance)
|
||||
{
|
||||
minChance = s - x;
|
||||
@ -304,8 +312,8 @@ namespace MWMechanics
|
||||
}
|
||||
}
|
||||
|
||||
float calcAutoCastChance(
|
||||
const ESM::Spell* spell, const int* actorSkills, const int* actorAttributes, int effectiveSchool)
|
||||
float calcAutoCastChance(const ESM::Spell* spell, const std::map<ESM::RefId, SkillValue>& actorSkills,
|
||||
const int* actorAttributes, int effectiveSchool)
|
||||
{
|
||||
if (spell->mData.mType != ESM::Spell::ST_Spell)
|
||||
return 100.f;
|
||||
@ -314,8 +322,10 @@ namespace MWMechanics
|
||||
return 100.f;
|
||||
|
||||
float skillTerm = 0;
|
||||
if (effectiveSchool != -1)
|
||||
skillTerm = 2.f * actorSkills[spellSchoolToSkill(effectiveSchool)];
|
||||
ESM::RefId skill = ESM::Skill::indexToRefId(spellSchoolToSkill(effectiveSchool));
|
||||
auto found = actorSkills.find(skill);
|
||||
if (found != actorSkills.end())
|
||||
skillTerm = 2.f * found->second.getBase();
|
||||
else
|
||||
calcWeakestSchool(
|
||||
spell, actorSkills, effectiveSchool, skillTerm); // Note effectiveSchool is unused after this
|
||||
|
@ -1,9 +1,12 @@
|
||||
#ifndef OPENMW_AUTOCALCSPELL_H
|
||||
#define OPENMW_AUTOCALCSPELL_H
|
||||
|
||||
#include "creaturestats.hpp"
|
||||
#include <components/esm/refid.hpp>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
struct Spell;
|
||||
@ -17,19 +20,21 @@ namespace MWMechanics
|
||||
/// @note We might want to move this code to a component later, so the editor can use it for preview purposes
|
||||
|
||||
std::vector<ESM::RefId> autoCalcNpcSpells(
|
||||
const int* actorSkills, const int* actorAttributes, const ESM::Race* race);
|
||||
const std::map<ESM::RefId, SkillValue>& actorSkills, const int* actorAttributes, const ESM::Race* race);
|
||||
|
||||
std::vector<ESM::RefId> autoCalcPlayerSpells(
|
||||
const int* actorSkills, const int* actorAttributes, const ESM::Race* race);
|
||||
const std::map<ESM::RefId, SkillValue>& actorSkills, const int* actorAttributes, const ESM::Race* race);
|
||||
|
||||
// Helpers
|
||||
|
||||
bool attrSkillCheck(const ESM::Spell* spell, const int* actorSkills, const int* actorAttributes);
|
||||
bool attrSkillCheck(
|
||||
const ESM::Spell* spell, const std::map<ESM::RefId, SkillValue>& actorSkills, const int* actorAttributes);
|
||||
|
||||
void calcWeakestSchool(const ESM::Spell* spell, const int* actorSkills, int& effectiveSchool, float& skillTerm);
|
||||
void calcWeakestSchool(const ESM::Spell* spell, const std::map<ESM::RefId, SkillValue>& actorSkills,
|
||||
int& effectiveSchool, float& skillTerm);
|
||||
|
||||
float calcAutoCastChance(
|
||||
const ESM::Spell* spell, const int* actorSkills, const int* actorAttributes, int effectiveSchool);
|
||||
float calcAutoCastChance(const ESM::Spell* spell, const std::map<ESM::RefId, SkillValue>& actorSkills,
|
||||
const int* actorAttributes, int effectiveSchool);
|
||||
|
||||
}
|
||||
|
||||
|
@ -122,7 +122,8 @@ namespace MWMechanics
|
||||
if (weapon.isEmpty())
|
||||
attackerSkill = attacker.getClass().getSkill(attacker, ESM::Skill::HandToHand);
|
||||
else
|
||||
attackerSkill = attacker.getClass().getSkill(attacker, weapon.getClass().getEquipmentSkill(weapon));
|
||||
attackerSkill = attacker.getClass().getSkill(
|
||||
attacker, ESM::Skill::indexToRefId(weapon.getClass().getEquipmentSkill(weapon)));
|
||||
float attackerTerm = attackerSkill + 0.2f * attackerStats.getAttribute(ESM::Attribute::Agility).getModified()
|
||||
+ 0.1f * attackerStats.getAttribute(ESM::Attribute::Luck).getModified();
|
||||
attackerTerm *= attackerStats.getFatigueTerm();
|
||||
@ -227,7 +228,7 @@ namespace MWMechanics
|
||||
if (attacker == getPlayer())
|
||||
MWBase::Environment::get().getWindowManager()->setEnemy(victim);
|
||||
|
||||
int skillValue = attacker.getClass().getSkill(attacker, weaponSkill);
|
||||
int skillValue = attacker.getClass().getSkill(attacker, ESM::Skill::indexToRefId(weaponSkill));
|
||||
|
||||
if (Misc::Rng::roll0to99(world->getPrng()) >= getHitChance(attacker, victim, skillValue))
|
||||
{
|
||||
|
@ -129,7 +129,7 @@ namespace MWMechanics
|
||||
creatureStats.getActiveSpells().clear(ptr);
|
||||
|
||||
for (size_t i = 0; i < player->mNpdt.mSkills.size(); ++i)
|
||||
npcStats.getSkill(i).setBase(player->mNpdt.mSkills[i]);
|
||||
npcStats.getSkill(ESM::Skill::indexToRefId(i)).setBase(player->mNpdt.mSkills[i]);
|
||||
|
||||
creatureStats.setAttribute(ESM::Attribute::Strength, player->mNpdt.mStrength);
|
||||
creatureStats.setAttribute(ESM::Attribute::Intelligence, player->mNpdt.mIntelligence);
|
||||
@ -164,7 +164,7 @@ namespace MWMechanics
|
||||
if (bonusIt != race->mData.mBonus.end())
|
||||
bonus = bonusIt->mBonus;
|
||||
|
||||
npcStats.getSkill(skill.mIndex).setBase(5 + bonus);
|
||||
npcStats.getSkill(skill.mId).setBase(5 + bonus);
|
||||
}
|
||||
|
||||
for (const ESM::RefId& power : race->mPowers.mList)
|
||||
@ -205,19 +205,16 @@ namespace MWMechanics
|
||||
|
||||
for (const auto& skills : class_->mData.mSkills)
|
||||
{
|
||||
int index = skills[i];
|
||||
|
||||
if (index >= 0 && index < ESM::Skill::Length)
|
||||
{
|
||||
npcStats.getSkill(index).setBase(npcStats.getSkill(index).getBase() + bonus);
|
||||
}
|
||||
ESM::RefId id = ESM::Skill::indexToRefId(skills[i]);
|
||||
if (!id.empty())
|
||||
npcStats.getSkill(id).setBase(npcStats.getSkill(id).getBase() + bonus);
|
||||
}
|
||||
}
|
||||
|
||||
for (const ESM::Skill& skill : esmStore.get<ESM::Skill>())
|
||||
{
|
||||
if (skill.mData.mSpecialization == class_->mData.mSpecialization)
|
||||
npcStats.getSkill(skill.mIndex).setBase(npcStats.getSkill(skill.mIndex).getBase() + 5);
|
||||
npcStats.getSkill(skill.mId).setBase(npcStats.getSkill(skill.mId).getBase() + 5);
|
||||
}
|
||||
}
|
||||
|
||||
@ -226,16 +223,12 @@ namespace MWMechanics
|
||||
if (mRaceSelected)
|
||||
race = esmStore.get<ESM::Race>().find(player->mRace);
|
||||
|
||||
int skills[ESM::Skill::Length];
|
||||
for (int i = 0; i < ESM::Skill::Length; ++i)
|
||||
skills[i] = npcStats.getSkill(i).getBase();
|
||||
|
||||
int attributes[ESM::Attribute::Length];
|
||||
for (int i = 0; i < ESM::Attribute::Length; ++i)
|
||||
attributes[i] = npcStats.getAttribute(i).getBase();
|
||||
npcStats.updateHealth();
|
||||
|
||||
std::vector<ESM::RefId> selectedSpells = autoCalcPlayerSpells(skills, attributes, race);
|
||||
std::vector<ESM::RefId> selectedSpells = autoCalcPlayerSpells(npcStats.getSkills(), attributes, race);
|
||||
|
||||
for (const ESM::RefId& spell : selectedSpells)
|
||||
creatureStats.getSpells().add(spell);
|
||||
@ -1914,7 +1907,7 @@ namespace MWMechanics
|
||||
const ESM::Skill* acrobatics
|
||||
= MWBase::Environment::get().getESMStore()->get<ESM::Skill>().find(ESM::Skill::Acrobatics);
|
||||
MWMechanics::NpcStats& stats = actor.getClass().getNpcStats(actor);
|
||||
auto& skill = stats.getSkill(acrobatics->mIndex);
|
||||
auto& skill = stats.getSkill(acrobatics->mId);
|
||||
skill.setModifier(acrobatics->mWerewolfValue - skill.getModified());
|
||||
}
|
||||
|
||||
|
@ -30,6 +30,8 @@ MWMechanics::NpcStats::NpcStats()
|
||||
{
|
||||
mSkillIncreases.resize(ESM::Attribute::Length, 0);
|
||||
mSpecIncreases.resize(3, 0);
|
||||
for (const ESM::Skill& skill : MWBase::Environment::get().getESMStore()->get<ESM::Skill>())
|
||||
mSkills.emplace(skill.mId, SkillValue{});
|
||||
}
|
||||
|
||||
int MWMechanics::NpcStats::getBaseDisposition() const
|
||||
@ -42,28 +44,28 @@ void MWMechanics::NpcStats::setBaseDisposition(int disposition)
|
||||
mDisposition = disposition;
|
||||
}
|
||||
|
||||
const MWMechanics::SkillValue& MWMechanics::NpcStats::getSkill(int index) const
|
||||
const MWMechanics::SkillValue& MWMechanics::NpcStats::getSkill(ESM::RefId id) const
|
||||
{
|
||||
if (index < 0 || index >= ESM::Skill::Length)
|
||||
throw std::runtime_error("skill index out of range");
|
||||
|
||||
return mSkill[index];
|
||||
auto it = mSkills.find(id);
|
||||
if (it == mSkills.end())
|
||||
throw std::runtime_error("skill not found");
|
||||
return it->second;
|
||||
}
|
||||
|
||||
MWMechanics::SkillValue& MWMechanics::NpcStats::getSkill(int index)
|
||||
MWMechanics::SkillValue& MWMechanics::NpcStats::getSkill(ESM::RefId id)
|
||||
{
|
||||
if (index < 0 || index >= ESM::Skill::Length)
|
||||
throw std::runtime_error("skill index out of range");
|
||||
|
||||
return mSkill[index];
|
||||
auto it = mSkills.find(id);
|
||||
if (it == mSkills.end())
|
||||
throw std::runtime_error("skill not found");
|
||||
return it->second;
|
||||
}
|
||||
|
||||
void MWMechanics::NpcStats::setSkill(int index, const MWMechanics::SkillValue& value)
|
||||
void MWMechanics::NpcStats::setSkill(ESM::RefId id, const MWMechanics::SkillValue& value)
|
||||
{
|
||||
if (index < 0 || index >= ESM::Skill::Length)
|
||||
throw std::runtime_error("skill index out of range");
|
||||
|
||||
mSkill[index] = value;
|
||||
auto it = mSkills.find(id);
|
||||
if (it == mSkills.end())
|
||||
throw std::runtime_error("skill not found");
|
||||
it->second = value;
|
||||
}
|
||||
|
||||
const std::map<ESM::RefId, int>& MWMechanics::NpcStats::getFactionRanks() const
|
||||
@ -154,22 +156,23 @@ void MWMechanics::NpcStats::setFactionReputation(const ESM::RefId& faction, int
|
||||
mFactionReputation[faction] = value;
|
||||
}
|
||||
|
||||
float MWMechanics::NpcStats::getSkillProgressRequirement(int skillIndex, const ESM::Class& class_) const
|
||||
float MWMechanics::NpcStats::getSkillProgressRequirement(ESM::RefId id, const ESM::Class& class_) const
|
||||
{
|
||||
float progressRequirement = static_cast<float>(1 + getSkill(skillIndex).getBase());
|
||||
float progressRequirement = 1.f + getSkill(id).getBase();
|
||||
|
||||
const MWWorld::Store<ESM::GameSetting>& gmst = MWBase::Environment::get().getESMStore()->get<ESM::GameSetting>();
|
||||
const ESM::Skill* skill = MWBase::Environment::get().getESMStore()->get<ESM::Skill>().find(id);
|
||||
|
||||
float typeFactor = gmst.find("fMiscSkillBonus")->mValue.getFloat();
|
||||
|
||||
for (const auto& skills : class_.mData.mSkills)
|
||||
{
|
||||
if (skills[0] == skillIndex)
|
||||
if (skills[0] == skill->mIndex)
|
||||
{
|
||||
typeFactor = gmst.find("fMinorSkillBonus")->mValue.getFloat();
|
||||
break;
|
||||
}
|
||||
else if (skills[1] == skillIndex)
|
||||
else if (skills[1] == skill->mIndex)
|
||||
{
|
||||
typeFactor = gmst.find("fMajorSkillBonus")->mValue.getFloat();
|
||||
break;
|
||||
@ -183,7 +186,6 @@ float MWMechanics::NpcStats::getSkillProgressRequirement(int skillIndex, const E
|
||||
|
||||
float specialisationFactor = 1;
|
||||
|
||||
const ESM::Skill* skill = MWBase::Environment::get().getESMStore()->get<ESM::Skill>().find(skillIndex);
|
||||
if (skill->mData.mSpecialization == class_.mData.mSpecialization)
|
||||
{
|
||||
specialisationFactor = gmst.find("fSpecialSkillBonus")->mValue.getFloat();
|
||||
@ -210,11 +212,11 @@ void MWMechanics::NpcStats::useSkill(int skillIndex, const ESM::Class& class_, i
|
||||
}
|
||||
skillGain *= extraFactor;
|
||||
|
||||
MWMechanics::SkillValue& value = getSkill(skillIndex);
|
||||
MWMechanics::SkillValue& value = getSkill(skill->mId);
|
||||
|
||||
value.setProgress(value.getProgress() + skillGain);
|
||||
|
||||
if (int(value.getProgress()) >= int(getSkillProgressRequirement(skillIndex, class_)))
|
||||
if (int(value.getProgress()) >= int(getSkillProgressRequirement(skill->mId, class_)))
|
||||
{
|
||||
// skill levelled up
|
||||
increaseSkill(skillIndex, class_, false);
|
||||
@ -224,7 +226,8 @@ void MWMechanics::NpcStats::useSkill(int skillIndex, const ESM::Class& class_, i
|
||||
void MWMechanics::NpcStats::increaseSkill(
|
||||
int skillIndex, const ESM::Class& class_, bool preserveProgress, bool readBook)
|
||||
{
|
||||
float base = getSkill(skillIndex).getBase();
|
||||
const ESM::Skill* skill = MWBase::Environment::get().getESMStore()->get<ESM::Skill>().find(skillIndex);
|
||||
float base = getSkill(skill->mId).getBase();
|
||||
|
||||
if (base >= 100.f)
|
||||
return;
|
||||
@ -251,7 +254,6 @@ void MWMechanics::NpcStats::increaseSkill(
|
||||
}
|
||||
}
|
||||
|
||||
const ESM::Skill* skill = MWBase::Environment::get().getESMStore()->get<ESM::Skill>().find(skillIndex);
|
||||
mSkillIncreases[skill->mData.mAttribute] += increase;
|
||||
|
||||
mSpecIncreases[skill->mData.mSpecialization] += gmst.find("iLevelupSpecialization")->mValue.getInteger();
|
||||
@ -275,9 +277,9 @@ void MWMechanics::NpcStats::increaseSkill(
|
||||
MWBase::Environment::get().getWindowManager()->messageBox("#{sLevelUpMsg}", MWGui::ShowInDialogueMode_Never);
|
||||
}
|
||||
|
||||
getSkill(skillIndex).setBase(base);
|
||||
getSkill(skill->mId).setBase(base);
|
||||
if (!preserveProgress)
|
||||
getSkill(skillIndex).setProgress(0);
|
||||
getSkill(skill->mId).setProgress(0);
|
||||
}
|
||||
|
||||
int MWMechanics::NpcStats::getLevelProgress() const
|
||||
@ -388,9 +390,10 @@ bool MWMechanics::NpcStats::hasSkillsForRank(const ESM::RefId& factionId, int ra
|
||||
|
||||
std::vector<int> skills;
|
||||
|
||||
for (int id : faction.mData.mSkills)
|
||||
for (int index : faction.mData.mSkills)
|
||||
{
|
||||
if (id != -1)
|
||||
ESM::RefId id = ESM::Skill::indexToRefId(index);
|
||||
if (!id.empty())
|
||||
skills.push_back(static_cast<int>(getSkill(id).getBase()));
|
||||
}
|
||||
|
||||
@ -470,8 +473,12 @@ void MWMechanics::NpcStats::writeState(ESM::NpcStats& state) const
|
||||
|
||||
state.mDisposition = mDisposition;
|
||||
|
||||
for (size_t i = 0; i < state.mSkills.size(); ++i)
|
||||
mSkill[i].writeState(state.mSkills[i]);
|
||||
for (const auto& [id, value] : mSkills)
|
||||
{
|
||||
// TODO extend format
|
||||
auto index = id.getIf<ESM::IndexRefId>()->getValue();
|
||||
value.writeState(state.mSkills[index]);
|
||||
}
|
||||
|
||||
state.mIsWerewolf = mIsWerewolf;
|
||||
|
||||
@ -524,7 +531,11 @@ void MWMechanics::NpcStats::readState(const ESM::NpcStats& state)
|
||||
mDisposition = state.mDisposition;
|
||||
|
||||
for (size_t i = 0; i < state.mSkills.size(); ++i)
|
||||
mSkill[i].readState(state.mSkills[i]);
|
||||
{
|
||||
// TODO extend format
|
||||
ESM::RefId id = ESM::Skill::indexToRefId(i);
|
||||
mSkills[id].readState(state.mSkills[i]);
|
||||
}
|
||||
|
||||
mIsWerewolf = state.mIsWerewolf;
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#include "creaturestats.hpp"
|
||||
#include <components/esm/refid.hpp>
|
||||
#include <components/esm3/loadskil.hpp>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <string>
|
||||
@ -21,7 +22,7 @@ namespace MWMechanics
|
||||
class NpcStats : public CreatureStats
|
||||
{
|
||||
int mDisposition;
|
||||
SkillValue mSkill[ESM::Skill::Length]; // SkillValue.mProgress used by the player only
|
||||
std::map<ESM::RefId, SkillValue> mSkills; // SkillValue.mProgress used by the player only
|
||||
|
||||
int mReputation;
|
||||
int mCrimeId;
|
||||
@ -58,9 +59,13 @@ namespace MWMechanics
|
||||
int getCrimeId() const;
|
||||
void setCrimeId(int id);
|
||||
|
||||
const SkillValue& getSkill(int index) const;
|
||||
SkillValue& getSkill(int index);
|
||||
void setSkill(int index, const SkillValue& value);
|
||||
const SkillValue& getSkill(ESM::RefId id) const;
|
||||
const SkillValue& getSkill(ESM::Skill::SkillEnum index) const
|
||||
{
|
||||
return getSkill(ESM::Skill::indexToRefId(index));
|
||||
}
|
||||
SkillValue& getSkill(ESM::RefId id);
|
||||
void setSkill(ESM::RefId id, const SkillValue& value);
|
||||
|
||||
int getFactionRank(const ESM::RefId& faction) const;
|
||||
const std::map<ESM::RefId, int>& getFactionRanks() const;
|
||||
@ -79,7 +84,7 @@ namespace MWMechanics
|
||||
|
||||
bool isInFaction(const ESM::RefId& faction) const;
|
||||
|
||||
float getSkillProgressRequirement(int skillIndex, const ESM::Class& class_) const;
|
||||
float getSkillProgressRequirement(ESM::RefId id, const ESM::Class& class_) const;
|
||||
|
||||
void useSkill(int skillIndex, const ESM::Class& class_, int usageType = -1, float extraFactor = 1.f);
|
||||
///< Increase skill by usage.
|
||||
@ -133,6 +138,8 @@ namespace MWMechanics
|
||||
|
||||
void readState(const ESM::CreatureStats& state);
|
||||
void readState(const ESM::NpcStats& state);
|
||||
|
||||
const std::map<ESM::RefId, SkillValue>& getSkills() const { return mSkills; }
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -105,7 +105,7 @@ namespace
|
||||
void damageSkill(const MWWorld::Ptr& target, const ESM::ActiveEffect& effect, float magnitude)
|
||||
{
|
||||
auto& npcStats = target.getClass().getNpcStats(target);
|
||||
auto& skill = npcStats.getSkill(effect.mArg);
|
||||
auto& skill = npcStats.getSkill(ESM::Skill::indexToRefId(effect.mArg));
|
||||
if (effect.mEffectId == ESM::MagicEffect::DamageSkill)
|
||||
magnitude = std::min(skill.getModified(), magnitude);
|
||||
skill.damage(magnitude);
|
||||
@ -114,14 +114,14 @@ namespace
|
||||
void restoreSkill(const MWWorld::Ptr& target, const ESM::ActiveEffect& effect, float magnitude)
|
||||
{
|
||||
auto& npcStats = target.getClass().getNpcStats(target);
|
||||
auto& skill = npcStats.getSkill(effect.mArg);
|
||||
auto& skill = npcStats.getSkill(ESM::Skill::indexToRefId(effect.mArg));
|
||||
skill.restore(magnitude);
|
||||
}
|
||||
|
||||
void fortifySkill(const MWWorld::Ptr& target, const ESM::ActiveEffect& effect, float magnitude)
|
||||
{
|
||||
auto& npcStats = target.getClass().getNpcStats(target);
|
||||
auto& skill = npcStats.getSkill(effect.mArg);
|
||||
auto& skill = npcStats.getSkill(ESM::Skill::indexToRefId(effect.mArg));
|
||||
skill.setModifier(skill.getModifier() + magnitude);
|
||||
}
|
||||
|
||||
@ -668,7 +668,7 @@ namespace MWMechanics
|
||||
if (spellParams.getType() == ESM::ActiveSpells::Type_Ability)
|
||||
{
|
||||
auto& npcStats = target.getClass().getNpcStats(target);
|
||||
SkillValue& skill = npcStats.getSkill(effect.mArg);
|
||||
SkillValue& skill = npcStats.getSkill(ESM::Skill::indexToRefId(effect.mArg));
|
||||
// Damage Skill abilities reduce base skill :todd:
|
||||
skill.setBase(std::max(skill.getBase() - effect.mMagnitude, 0.f));
|
||||
}
|
||||
@ -760,7 +760,7 @@ namespace MWMechanics
|
||||
{
|
||||
// Abilities affect base stats, but not for drain
|
||||
auto& npcStats = target.getClass().getNpcStats(target);
|
||||
auto& skill = npcStats.getSkill(effect.mArg);
|
||||
auto& skill = npcStats.getSkill(ESM::Skill::indexToRefId(effect.mArg));
|
||||
skill.setBase(skill.getBase() + effect.mMagnitude);
|
||||
}
|
||||
else
|
||||
@ -1218,7 +1218,7 @@ namespace MWMechanics
|
||||
if (spellParams.getType() == ESM::ActiveSpells::Type_Ability)
|
||||
{
|
||||
auto& npcStats = target.getClass().getNpcStats(target);
|
||||
auto& skill = npcStats.getSkill(effect.mArg);
|
||||
auto& skill = npcStats.getSkill(ESM::Skill::indexToRefId(effect.mArg));
|
||||
skill.setBase(skill.getBase() - effect.mMagnitude);
|
||||
}
|
||||
else
|
||||
|
@ -565,7 +565,7 @@ namespace MWMechanics
|
||||
case ESM::MagicEffect::DrainSkill:
|
||||
if (enemy.isEmpty() || !enemy.getClass().isNpc())
|
||||
return 0.f;
|
||||
if (enemy.getClass().getSkill(enemy, effect.mSkill) <= 0)
|
||||
if (enemy.getClass().getSkill(enemy, ESM::Skill::indexToRefId(effect.mSkill)) <= 0)
|
||||
return 0.f;
|
||||
break;
|
||||
|
||||
|
@ -120,8 +120,8 @@ namespace MWMechanics
|
||||
int value = 50.f;
|
||||
if (actor.getClass().isNpc())
|
||||
{
|
||||
int skill = item.getClass().getEquipmentSkill(item);
|
||||
if (skill != -1)
|
||||
ESM::RefId skill = ESM::Skill::indexToRefId(item.getClass().getEquipmentSkill(item));
|
||||
if (!skill.empty())
|
||||
value = actor.getClass().getSkill(actor, skill);
|
||||
}
|
||||
else
|
||||
@ -179,7 +179,9 @@ namespace MWMechanics
|
||||
if (weapon.isEmpty())
|
||||
return 0.f;
|
||||
|
||||
float skillMult = actor.getClass().getSkill(actor, weapon.getClass().getEquipmentSkill(weapon)) * 0.01f;
|
||||
float skillMult
|
||||
= actor.getClass().getSkill(actor, ESM::Skill::indexToRefId(weapon.getClass().getEquipmentSkill(weapon)))
|
||||
* 0.01f;
|
||||
float chopMult = fAIMeleeWeaponMult;
|
||||
float bonusDamage = 0.f;
|
||||
|
||||
|
@ -345,11 +345,11 @@ namespace MWScript
|
||||
template <class R>
|
||||
class OpGetSkill : public Interpreter::Opcode0
|
||||
{
|
||||
int mIndex;
|
||||
ESM::RefId mId;
|
||||
|
||||
public:
|
||||
OpGetSkill(int index)
|
||||
: mIndex(index)
|
||||
OpGetSkill(ESM::RefId id)
|
||||
: mId(id)
|
||||
{
|
||||
}
|
||||
|
||||
@ -357,7 +357,7 @@ namespace MWScript
|
||||
{
|
||||
MWWorld::Ptr ptr = R()(runtime);
|
||||
|
||||
Interpreter::Type_Float value = ptr.getClass().getSkill(ptr, mIndex);
|
||||
Interpreter::Type_Float value = ptr.getClass().getSkill(ptr, mId);
|
||||
|
||||
runtime.push(value);
|
||||
}
|
||||
@ -366,11 +366,11 @@ namespace MWScript
|
||||
template <class R>
|
||||
class OpSetSkill : public Interpreter::Opcode0
|
||||
{
|
||||
int mIndex;
|
||||
ESM::RefId mId;
|
||||
|
||||
public:
|
||||
OpSetSkill(int index)
|
||||
: mIndex(index)
|
||||
OpSetSkill(ESM::RefId id)
|
||||
: mId(id)
|
||||
{
|
||||
}
|
||||
|
||||
@ -383,18 +383,18 @@ namespace MWScript
|
||||
|
||||
MWMechanics::NpcStats& stats = ptr.getClass().getNpcStats(ptr);
|
||||
|
||||
stats.getSkill(mIndex).setBase(value, true);
|
||||
stats.getSkill(mId).setBase(value, true);
|
||||
}
|
||||
};
|
||||
|
||||
template <class R>
|
||||
class OpModSkill : public Interpreter::Opcode0
|
||||
{
|
||||
int mIndex;
|
||||
ESM::RefId mId;
|
||||
|
||||
public:
|
||||
OpModSkill(int index)
|
||||
: mIndex(index)
|
||||
OpModSkill(ESM::RefId id)
|
||||
: mId(id)
|
||||
{
|
||||
}
|
||||
|
||||
@ -405,7 +405,7 @@ namespace MWScript
|
||||
Interpreter::Type_Float value = runtime[0].mFloat;
|
||||
runtime.pop();
|
||||
|
||||
MWMechanics::SkillValue& skill = ptr.getClass().getNpcStats(ptr).getSkill(mIndex);
|
||||
MWMechanics::SkillValue& skill = ptr.getClass().getNpcStats(ptr).getSkill(mId);
|
||||
modStat(skill, value);
|
||||
}
|
||||
};
|
||||
@ -1364,14 +1364,15 @@ namespace MWScript
|
||||
|
||||
for (int i = 0; i < Compiler::Stats::numberOfSkills; ++i)
|
||||
{
|
||||
interpreter.installSegment5<OpGetSkill<ImplicitRef>>(Compiler::Stats::opcodeGetSkill + i, i);
|
||||
interpreter.installSegment5<OpGetSkill<ExplicitRef>>(Compiler::Stats::opcodeGetSkillExplicit + i, i);
|
||||
ESM::RefId id = ESM::Skill::indexToRefId(i);
|
||||
interpreter.installSegment5<OpGetSkill<ImplicitRef>>(Compiler::Stats::opcodeGetSkill + i, id);
|
||||
interpreter.installSegment5<OpGetSkill<ExplicitRef>>(Compiler::Stats::opcodeGetSkillExplicit + i, id);
|
||||
|
||||
interpreter.installSegment5<OpSetSkill<ImplicitRef>>(Compiler::Stats::opcodeSetSkill + i, i);
|
||||
interpreter.installSegment5<OpSetSkill<ExplicitRef>>(Compiler::Stats::opcodeSetSkillExplicit + i, i);
|
||||
interpreter.installSegment5<OpSetSkill<ImplicitRef>>(Compiler::Stats::opcodeSetSkill + i, id);
|
||||
interpreter.installSegment5<OpSetSkill<ExplicitRef>>(Compiler::Stats::opcodeSetSkillExplicit + i, id);
|
||||
|
||||
interpreter.installSegment5<OpModSkill<ImplicitRef>>(Compiler::Stats::opcodeModSkill + i, i);
|
||||
interpreter.installSegment5<OpModSkill<ExplicitRef>>(Compiler::Stats::opcodeModSkillExplicit + i, i);
|
||||
interpreter.installSegment5<OpModSkill<ImplicitRef>>(Compiler::Stats::opcodeModSkill + i, id);
|
||||
interpreter.installSegment5<OpModSkill<ExplicitRef>>(Compiler::Stats::opcodeModSkillExplicit + i, id);
|
||||
}
|
||||
|
||||
interpreter.installSegment5<OpGetPCCrimeLevel>(Compiler::Stats::opcodeGetPCCrimeLevel);
|
||||
|
@ -438,7 +438,7 @@ namespace MWWorld
|
||||
return canSwim(ptr) || canWalk(ptr) || canFly(ptr);
|
||||
}
|
||||
|
||||
float Class::getSkill(const MWWorld::Ptr& ptr, int skill) const
|
||||
float Class::getSkill(const MWWorld::Ptr& ptr, ESM::RefId id) const
|
||||
{
|
||||
throw std::runtime_error("class does not support skills");
|
||||
}
|
||||
|
@ -14,6 +14,7 @@
|
||||
|
||||
#include "../mwmechanics/aisetting.hpp"
|
||||
#include <components/esm/refid.hpp>
|
||||
#include <components/esm3/loadskil.hpp>
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
@ -340,7 +341,11 @@ namespace MWWorld
|
||||
bool isPureLandCreature(const MWWorld::Ptr& ptr) const;
|
||||
bool isMobile(const MWWorld::Ptr& ptr) const;
|
||||
|
||||
virtual float getSkill(const MWWorld::Ptr& ptr, int skill) const;
|
||||
virtual float getSkill(const MWWorld::Ptr& ptr, ESM::RefId id) const;
|
||||
float getSkill(const MWWorld::Ptr& ptr, ESM::Skill::SkillEnum index) const
|
||||
{
|
||||
return getSkill(ptr, ESM::Skill::indexToRefId(index));
|
||||
};
|
||||
|
||||
virtual void readAdditionalState(const MWWorld::Ptr& ptr, const ESM::ObjectState& state) const;
|
||||
///< Read additional state from \a state into \a ptr.
|
||||
|
@ -285,7 +285,7 @@ void MWWorld::InventoryStore::autoEquipWeapon(TSlots& slots_)
|
||||
|
||||
for (int j = 0; j < static_cast<int>(weaponSkillsLength); ++j)
|
||||
{
|
||||
float skillValue = mActor.getClass().getSkill(mActor, static_cast<int>(weaponSkills[j]));
|
||||
float skillValue = mActor.getClass().getSkill(mActor, weaponSkills[j]);
|
||||
if (skillValue > max && !weaponSkillVisited[j])
|
||||
{
|
||||
max = skillValue;
|
||||
|
@ -59,23 +59,23 @@ namespace MWWorld
|
||||
{
|
||||
MWMechanics::NpcStats& stats = getPlayer().getClass().getNpcStats(getPlayer());
|
||||
|
||||
for (int i = 0; i < ESM::Skill::Length; ++i)
|
||||
mSaveSkills[i] = stats.getSkill(i).getModified();
|
||||
for (size_t i = 0; i < mSaveSkills.size(); ++i)
|
||||
mSaveSkills[i] = stats.getSkill(ESM::Skill::indexToRefId(i)).getModified();
|
||||
for (int i = 0; i < ESM::Attribute::Length; ++i)
|
||||
mSaveAttributes[i] = stats.getAttribute(i).getModified();
|
||||
}
|
||||
|
||||
void Player::restoreStats()
|
||||
{
|
||||
const MWWorld::Store<ESM::GameSetting>& gmst
|
||||
= MWBase::Environment::get().getESMStore()->get<ESM::GameSetting>();
|
||||
const auto& store = MWBase::Environment::get().getESMStore();
|
||||
const MWWorld::Store<ESM::GameSetting>& gmst = store->get<ESM::GameSetting>();
|
||||
MWMechanics::CreatureStats& creatureStats = getPlayer().getClass().getCreatureStats(getPlayer());
|
||||
MWMechanics::NpcStats& npcStats = getPlayer().getClass().getNpcStats(getPlayer());
|
||||
MWMechanics::DynamicStat<float> health = creatureStats.getDynamic(0);
|
||||
creatureStats.setHealth(health.getBase() / gmst.find("fWereWolfHealth")->mValue.getFloat());
|
||||
for (int i = 0; i < ESM::Skill::Length; ++i)
|
||||
for (size_t i = 0; i < mSaveSkills.size(); ++i)
|
||||
{
|
||||
auto& skill = npcStats.getSkill(i);
|
||||
auto& skill = npcStats.getSkill(ESM::Skill::indexToRefId(i));
|
||||
skill.restore(skill.getDamage());
|
||||
skill.setModifier(mSaveSkills[i] - skill.getBase());
|
||||
}
|
||||
@ -109,7 +109,7 @@ namespace MWWorld
|
||||
if (skill.mIndex == ESM::Skill::Acrobatics)
|
||||
continue;
|
||||
|
||||
MWMechanics::SkillValue& value = npcStats.getSkill(skill.mIndex);
|
||||
MWMechanics::SkillValue& value = npcStats.getSkill(skill.mId);
|
||||
value.setModifier(skill.mWerewolfValue - value.getModified());
|
||||
}
|
||||
}
|
||||
@ -251,10 +251,7 @@ namespace MWWorld
|
||||
mPreviousItems.clear();
|
||||
mLastKnownExteriorPosition = osg::Vec3f(0, 0, 0);
|
||||
|
||||
for (int i = 0; i < ESM::Skill::Length; ++i)
|
||||
{
|
||||
mSaveSkills[i] = 0.f;
|
||||
}
|
||||
mSaveSkills.fill(0.f);
|
||||
|
||||
for (int i = 0; i < ESM::Attribute::Length; ++i)
|
||||
{
|
||||
@ -296,7 +293,7 @@ namespace MWWorld
|
||||
|
||||
for (int i = 0; i < ESM::Attribute::Length; ++i)
|
||||
player.mSaveAttributes[i] = mSaveAttributes[i];
|
||||
for (int i = 0; i < ESM::Skill::Length; ++i)
|
||||
for (size_t i = 0; i < mSaveSkills.size(); ++i)
|
||||
player.mSaveSkills[i] = mSaveSkills[i];
|
||||
|
||||
player.mPreviousItems = mPreviousItems;
|
||||
@ -334,7 +331,7 @@ namespace MWWorld
|
||||
|
||||
for (int i = 0; i < ESM::Attribute::Length; ++i)
|
||||
mSaveAttributes[i] = player.mSaveAttributes[i];
|
||||
for (int i = 0; i < ESM::Skill::Length; ++i)
|
||||
for (size_t i = 0; i < mSaveSkills.size(); ++i)
|
||||
mSaveSkills[i] = player.mSaveSkills[i];
|
||||
|
||||
if (player.mObject.mNpcStats.mIsWerewolf)
|
||||
|
@ -1,6 +1,7 @@
|
||||
#ifndef GAME_MWWORLD_PLAYER_H
|
||||
#define GAME_MWWORLD_PLAYER_H
|
||||
|
||||
#include <array>
|
||||
#include <map>
|
||||
|
||||
#include "../mwworld/livecellref.hpp"
|
||||
@ -50,7 +51,7 @@ namespace MWWorld
|
||||
PreviousItems mPreviousItems;
|
||||
|
||||
// Saved stats prior to becoming a werewolf
|
||||
float mSaveSkills[ESM::Skill::Length];
|
||||
std::array<float, ESM::Skill::Length> mSaveSkills;
|
||||
float mSaveAttributes[ESM::Attribute::Length];
|
||||
|
||||
bool mJumping;
|
||||
|
Loading…
x
Reference in New Issue
Block a user