mirror of
https://github.com/OpenMW/openmw.git
synced 2026-01-03 17:13:06 +00:00
Maybe an anonymous namespace reduces RAM requirements
This file is the most likely to make the compiler run out of heap space
This commit is contained in:
parent
93c3618121
commit
f884c26631
1 changed files with 410 additions and 401 deletions
|
|
@ -62,428 +62,437 @@ namespace
|
|||
|
||||
namespace MWLua
|
||||
{
|
||||
static void addStatUpdateAction(MWLua::LuaManager* manager, const SelfObject& obj)
|
||||
namespace
|
||||
{
|
||||
if (!obj.mStatsCache.empty())
|
||||
return; // was already added before
|
||||
manager->addAction(
|
||||
[obj = Object(obj)] {
|
||||
LocalScripts* scripts = obj.ptr().getRefData().getLuaScripts();
|
||||
if (scripts)
|
||||
scripts->applyStatsCache();
|
||||
},
|
||||
"StatUpdateAction");
|
||||
}
|
||||
|
||||
static void setCreatureValue(Index, std::string_view prop, const MWWorld::Ptr& ptr, const sol::object& value)
|
||||
{
|
||||
auto& stats = ptr.getClass().getCreatureStats(ptr);
|
||||
if (prop == "current")
|
||||
stats.setLevel(LuaUtil::cast<int>(value));
|
||||
}
|
||||
|
||||
static void setNpcValue(Index index, std::string_view prop, const MWWorld::Ptr& ptr, const sol::object& value)
|
||||
{
|
||||
auto& stats = ptr.getClass().getNpcStats(ptr);
|
||||
if (prop == "progress")
|
||||
stats.setLevelProgress(LuaUtil::cast<int>(value));
|
||||
else if (prop == "skillIncreasesForAttribute")
|
||||
stats.setSkillIncreasesForAttribute(
|
||||
*std::get<ESM::RefId>(index).getIf<ESM::StringRefId>(), LuaUtil::cast<int>(value));
|
||||
else if (prop == "skillIncreasesForSpecialization")
|
||||
stats.setSkillIncreasesForSpecialization(
|
||||
static_cast<ESM::Class::Specialization>(std::get<int>(index)), LuaUtil::cast<int>(value));
|
||||
}
|
||||
|
||||
class SkillIncreasesForAttributeStats
|
||||
{
|
||||
ObjectVariant mObject;
|
||||
|
||||
public:
|
||||
SkillIncreasesForAttributeStats(ObjectVariant object)
|
||||
: mObject(std::move(object))
|
||||
static void addStatUpdateAction(MWLua::LuaManager* manager, const SelfObject& obj)
|
||||
{
|
||||
if (!obj.mStatsCache.empty())
|
||||
return; // was already added before
|
||||
manager->addAction(
|
||||
[obj = Object(obj)] {
|
||||
LocalScripts* scripts = obj.ptr().getRefData().getLuaScripts();
|
||||
if (scripts)
|
||||
scripts->applyStatsCache();
|
||||
},
|
||||
"StatUpdateAction");
|
||||
}
|
||||
|
||||
sol::object get(const Context& context, ESM::StringRefId attributeId) const
|
||||
static void setCreatureValue(Index, std::string_view prop, const MWWorld::Ptr& ptr, const sol::object& value)
|
||||
{
|
||||
if (!mObject.ptr().getClass().isNpc())
|
||||
return sol::nil;
|
||||
|
||||
return getValue(context, mObject, &setNpcValue, attributeId, "skillIncreasesForAttribute",
|
||||
[attributeId](const MWWorld::Ptr& ptr) {
|
||||
return ptr.getClass().getNpcStats(ptr).getSkillIncreasesForAttribute(attributeId);
|
||||
});
|
||||
}
|
||||
|
||||
void set(const Context& context, ESM::StringRefId attributeId, const sol::object& value) const
|
||||
{
|
||||
const auto& ptr = mObject.ptr();
|
||||
if (!ptr.getClass().isNpc())
|
||||
return;
|
||||
|
||||
SelfObject* obj = mObject.asSelfObject();
|
||||
addStatUpdateAction(context.mLuaManager, *obj);
|
||||
obj->mStatsCache[SelfObject::CachedStat{ &setNpcValue, attributeId, "skillIncreasesForAttribute" }]
|
||||
= sol::main_object(value);
|
||||
}
|
||||
};
|
||||
|
||||
class SkillIncreasesForSpecializationStats
|
||||
{
|
||||
ObjectVariant mObject;
|
||||
|
||||
public:
|
||||
SkillIncreasesForSpecializationStats(ObjectVariant object)
|
||||
: mObject(std::move(object))
|
||||
{
|
||||
}
|
||||
|
||||
sol::object get(const Context& context, int specialization) const
|
||||
{
|
||||
if (!mObject.ptr().getClass().isNpc())
|
||||
return sol::nil;
|
||||
|
||||
return getValue(context, mObject, &setNpcValue, specialization, "skillIncreasesForSpecialization",
|
||||
[specialization](const MWWorld::Ptr& ptr) {
|
||||
return ptr.getClass().getNpcStats(ptr).getSkillIncreasesForSpecialization(
|
||||
static_cast<ESM::Class::Specialization>(specialization));
|
||||
});
|
||||
}
|
||||
|
||||
void set(const Context& context, int specialization, const sol::object& value) const
|
||||
{
|
||||
const auto& ptr = mObject.ptr();
|
||||
if (!ptr.getClass().isNpc())
|
||||
return;
|
||||
|
||||
SelfObject* obj = mObject.asSelfObject();
|
||||
addStatUpdateAction(context.mLuaManager, *obj);
|
||||
obj->mStatsCache[SelfObject::CachedStat{ &setNpcValue, specialization, "skillIncreasesForSpecialization" }]
|
||||
= sol::main_object(value);
|
||||
}
|
||||
};
|
||||
|
||||
class LevelStat
|
||||
{
|
||||
ObjectVariant mObject;
|
||||
|
||||
LevelStat(ObjectVariant object)
|
||||
: mObject(std::move(object))
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
sol::object getCurrent(const Context& context) const
|
||||
{
|
||||
return getValue(context, mObject, &setCreatureValue, std::monostate{}, "current",
|
||||
[](const MWWorld::Ptr& ptr) { return ptr.getClass().getCreatureStats(ptr).getLevel(); });
|
||||
}
|
||||
|
||||
void setCurrent(const Context& context, const sol::object& value) const
|
||||
{
|
||||
SelfObject* obj = mObject.asSelfObject();
|
||||
addStatUpdateAction(context.mLuaManager, *obj);
|
||||
obj->mStatsCache[SelfObject::CachedStat{ &setCreatureValue, std::monostate{}, "current" }]
|
||||
= sol::main_object(value);
|
||||
}
|
||||
|
||||
sol::object getProgress(const Context& context) const
|
||||
{
|
||||
if (!mObject.ptr().getClass().isNpc())
|
||||
return sol::nil;
|
||||
|
||||
return getValue(context, mObject, &setNpcValue, std::monostate{}, "progress",
|
||||
[](const MWWorld::Ptr& ptr) { return ptr.getClass().getNpcStats(ptr).getLevelProgress(); });
|
||||
}
|
||||
|
||||
void setProgress(const Context& context, const sol::object& value) const
|
||||
{
|
||||
const auto& ptr = mObject.ptr();
|
||||
if (!ptr.getClass().isNpc())
|
||||
return;
|
||||
|
||||
SelfObject* obj = mObject.asSelfObject();
|
||||
addStatUpdateAction(context.mLuaManager, *obj);
|
||||
obj->mStatsCache[SelfObject::CachedStat{ &setNpcValue, std::monostate{}, "progress" }]
|
||||
= sol::main_object(value);
|
||||
}
|
||||
|
||||
SkillIncreasesForAttributeStats getSkillIncreasesForAttributeStats() const
|
||||
{
|
||||
return SkillIncreasesForAttributeStats{ mObject };
|
||||
}
|
||||
|
||||
SkillIncreasesForSpecializationStats getSkillIncreasesForSpecializationStats() const
|
||||
{
|
||||
return SkillIncreasesForSpecializationStats{ mObject };
|
||||
}
|
||||
|
||||
static std::optional<LevelStat> create(ObjectVariant object, Index)
|
||||
{
|
||||
if (!object.ptr().getClass().isActor())
|
||||
return {};
|
||||
return LevelStat{ std::move(object) };
|
||||
}
|
||||
};
|
||||
|
||||
class DynamicStat
|
||||
{
|
||||
ObjectVariant mObject;
|
||||
int mIndex;
|
||||
|
||||
DynamicStat(ObjectVariant object, int index)
|
||||
: mObject(std::move(object))
|
||||
, mIndex(index)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
template <class G>
|
||||
sol::object get(const Context& context, std::string_view prop, G getter) const
|
||||
{
|
||||
return getValue(
|
||||
context, mObject, &DynamicStat::setValue, mIndex, prop, [this, getter](const MWWorld::Ptr& ptr) {
|
||||
return (ptr.getClass().getCreatureStats(ptr).getDynamic(mIndex).*getter)();
|
||||
});
|
||||
}
|
||||
|
||||
static std::optional<DynamicStat> create(ObjectVariant object, Index i)
|
||||
{
|
||||
if (!object.ptr().getClass().isActor())
|
||||
return {};
|
||||
int index = std::get<int>(i);
|
||||
return DynamicStat{ std::move(object), index };
|
||||
}
|
||||
|
||||
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{ &DynamicStat::setValue, mIndex, prop }] = sol::main_object(value);
|
||||
}
|
||||
|
||||
static void setValue(Index i, std::string_view prop, const MWWorld::Ptr& ptr, const sol::object& value)
|
||||
{
|
||||
int index = std::get<int>(i);
|
||||
auto& stats = ptr.getClass().getCreatureStats(ptr);
|
||||
auto stat = stats.getDynamic(index);
|
||||
float floatValue = LuaUtil::cast<float>(value);
|
||||
if (prop == "base")
|
||||
stat.setBase(floatValue);
|
||||
else if (prop == "current")
|
||||
stat.setCurrent(floatValue, true, true);
|
||||
else if (prop == "modifier")
|
||||
stat.setModifier(floatValue);
|
||||
stats.setDynamic(index, stat);
|
||||
}
|
||||
};
|
||||
|
||||
class AttributeStat
|
||||
{
|
||||
ObjectVariant mObject;
|
||||
ESM::RefId mId;
|
||||
|
||||
AttributeStat(ObjectVariant object, ESM::RefId id)
|
||||
: mObject(std::move(object))
|
||||
, mId(id)
|
||||
{
|
||||
if (prop == "current")
|
||||
stats.setLevel(LuaUtil::cast<int>(value));
|
||||
}
|
||||
|
||||
public:
|
||||
template <class G>
|
||||
sol::object get(const Context& context, std::string_view prop, G getter) const
|
||||
static void setNpcValue(Index index, std::string_view prop, const MWWorld::Ptr& ptr, const sol::object& value)
|
||||
{
|
||||
return getValue(
|
||||
context, mObject, &AttributeStat::setValue, mId, prop, [this, getter](const MWWorld::Ptr& ptr) {
|
||||
return (ptr.getClass().getCreatureStats(ptr).getAttribute(mId).*getter)();
|
||||
});
|
||||
}
|
||||
|
||||
float getModified(const Context& context) const
|
||||
{
|
||||
auto base = LuaUtil::cast<float>(get(context, "base", &MWMechanics::AttributeValue::getBase));
|
||||
auto damage = LuaUtil::cast<float>(get(context, "damage", &MWMechanics::AttributeValue::getDamage));
|
||||
auto modifier = LuaUtil::cast<float>(get(context, "modifier", &MWMechanics::AttributeValue::getModifier));
|
||||
return std::max(0.f, base - damage + modifier); // Should match AttributeValue::getModified
|
||||
}
|
||||
|
||||
static std::optional<AttributeStat> create(ObjectVariant object, Index i)
|
||||
{
|
||||
if (!object.ptr().getClass().isActor())
|
||||
return {};
|
||||
ESM::RefId id = std::get<ESM::RefId>(i);
|
||||
return AttributeStat{ 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{ &AttributeStat::setValue, mId, prop }] = sol::main_object(value);
|
||||
}
|
||||
|
||||
static void setValue(Index i, std::string_view prop, const MWWorld::Ptr& ptr, const sol::object& value)
|
||||
{
|
||||
ESM::RefId id = std::get<ESM::RefId>(i);
|
||||
auto& stats = ptr.getClass().getCreatureStats(ptr);
|
||||
auto stat = stats.getAttribute(id);
|
||||
float floatValue = LuaUtil::cast<float>(value);
|
||||
if (prop == "base")
|
||||
stat.setBase(floatValue);
|
||||
else if (prop == "damage")
|
||||
{
|
||||
stat.restore(stat.getDamage());
|
||||
stat.damage(floatValue);
|
||||
}
|
||||
else if (prop == "modifier")
|
||||
stat.setModifier(floatValue);
|
||||
stats.setAttribute(id, stat);
|
||||
}
|
||||
};
|
||||
|
||||
class SkillStat
|
||||
{
|
||||
ObjectVariant mObject;
|
||||
ESM::RefId mId;
|
||||
|
||||
SkillStat(ObjectVariant object, ESM::RefId id)
|
||||
: mObject(std::move(object))
|
||||
, mId(id)
|
||||
{
|
||||
}
|
||||
|
||||
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, id, stat);
|
||||
return progress;
|
||||
}
|
||||
|
||||
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(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, mId, prop, [this, getter](const MWWorld::Ptr& ptr) {
|
||||
return (ptr.getClass().getNpcStats(ptr).getSkill(mId).*getter)();
|
||||
});
|
||||
}
|
||||
|
||||
float getModified(const Context& context) const
|
||||
{
|
||||
auto base = LuaUtil::cast<float>(get(context, "base", &MWMechanics::SkillValue::getBase));
|
||||
auto damage = LuaUtil::cast<float>(get(context, "damage", &MWMechanics::SkillValue::getDamage));
|
||||
auto modifier = LuaUtil::cast<float>(get(context, "modifier", &MWMechanics::SkillValue::getModifier));
|
||||
return std::max(0.f, base - damage + modifier); // Should match SkillValue::getModified
|
||||
}
|
||||
|
||||
sol::object getProgress(const Context& context) const
|
||||
{
|
||||
return getValue(context, mObject, &SkillStat::setValue, mId, "progress", [this](const MWWorld::Ptr& ptr) {
|
||||
return getProgress(ptr, mId, ptr.getClass().getNpcStats(ptr).getSkill(mId));
|
||||
});
|
||||
}
|
||||
|
||||
static std::optional<SkillStat> create(ObjectVariant object, Index index)
|
||||
{
|
||||
if (!object.ptr().getClass().isNpc())
|
||||
return {};
|
||||
ESM::RefId id = std::get<ESM::RefId>(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, mId, prop }] = sol::main_object(value);
|
||||
}
|
||||
|
||||
static void setValue(Index index, std::string_view prop, const MWWorld::Ptr& ptr, const sol::object& value)
|
||||
{
|
||||
ESM::RefId id = std::get<ESM::RefId>(index);
|
||||
auto& stats = ptr.getClass().getNpcStats(ptr);
|
||||
auto stat = stats.getSkill(id);
|
||||
float floatValue = LuaUtil::cast<float>(value);
|
||||
if (prop == "base")
|
||||
stat.setBase(floatValue);
|
||||
else if (prop == "damage")
|
||||
if (prop == "progress")
|
||||
stats.setLevelProgress(LuaUtil::cast<int>(value));
|
||||
else if (prop == "skillIncreasesForAttribute")
|
||||
stats.setSkillIncreasesForAttribute(
|
||||
*std::get<ESM::RefId>(index).getIf<ESM::StringRefId>(), LuaUtil::cast<int>(value));
|
||||
else if (prop == "skillIncreasesForSpecialization")
|
||||
stats.setSkillIncreasesForSpecialization(
|
||||
static_cast<ESM::Class::Specialization>(std::get<int>(index)), LuaUtil::cast<int>(value));
|
||||
}
|
||||
|
||||
class SkillIncreasesForAttributeStats
|
||||
{
|
||||
ObjectVariant mObject;
|
||||
|
||||
public:
|
||||
SkillIncreasesForAttributeStats(ObjectVariant object)
|
||||
: mObject(std::move(object))
|
||||
{
|
||||
stat.restore(stat.getDamage());
|
||||
stat.damage(floatValue);
|
||||
}
|
||||
else if (prop == "modifier")
|
||||
stat.setModifier(floatValue);
|
||||
else if (prop == "progress")
|
||||
stat.setProgress(floatValue * getMaxProgress(ptr, id, stat));
|
||||
stats.setSkill(id, stat);
|
||||
}
|
||||
};
|
||||
|
||||
class AIStat
|
||||
{
|
||||
ObjectVariant mObject;
|
||||
MWMechanics::AiSetting mIndex;
|
||||
sol::object get(const Context& context, ESM::StringRefId attributeId) const
|
||||
{
|
||||
if (!mObject.ptr().getClass().isNpc())
|
||||
return sol::nil;
|
||||
|
||||
AIStat(ObjectVariant object, MWMechanics::AiSetting index)
|
||||
: mObject(std::move(object))
|
||||
, mIndex(index)
|
||||
return getValue(context, mObject, &setNpcValue, attributeId, "skillIncreasesForAttribute",
|
||||
[attributeId](const MWWorld::Ptr& ptr) {
|
||||
return ptr.getClass().getNpcStats(ptr).getSkillIncreasesForAttribute(attributeId);
|
||||
});
|
||||
}
|
||||
|
||||
void set(const Context& context, ESM::StringRefId attributeId, const sol::object& value) const
|
||||
{
|
||||
const auto& ptr = mObject.ptr();
|
||||
if (!ptr.getClass().isNpc())
|
||||
return;
|
||||
|
||||
SelfObject* obj = mObject.asSelfObject();
|
||||
addStatUpdateAction(context.mLuaManager, *obj);
|
||||
obj->mStatsCache[SelfObject::CachedStat{ &setNpcValue, attributeId, "skillIncreasesForAttribute" }]
|
||||
= sol::main_object(value);
|
||||
}
|
||||
};
|
||||
|
||||
class SkillIncreasesForSpecializationStats
|
||||
{
|
||||
}
|
||||
ObjectVariant mObject;
|
||||
|
||||
public:
|
||||
template <class G>
|
||||
sol::object get(const Context& context, std::string_view prop, G getter) const
|
||||
{
|
||||
return getValue(context, mObject, &AIStat::setValue, static_cast<int>(mIndex), prop,
|
||||
[this, getter](const MWWorld::Ptr& ptr) {
|
||||
return (ptr.getClass().getCreatureStats(ptr).getAiSetting(mIndex).*getter)();
|
||||
});
|
||||
}
|
||||
public:
|
||||
SkillIncreasesForSpecializationStats(ObjectVariant object)
|
||||
: mObject(std::move(object))
|
||||
{
|
||||
}
|
||||
|
||||
int getModified(const Context& context) const
|
||||
{
|
||||
auto base = LuaUtil::cast<int>(get(context, "base", &MWMechanics::Stat<int>::getBase));
|
||||
auto modifier = LuaUtil::cast<int>(get(context, "modifier", &MWMechanics::Stat<int>::getModifier));
|
||||
return std::max(0, base + modifier);
|
||||
}
|
||||
sol::object get(const Context& context, int specialization) const
|
||||
{
|
||||
if (!mObject.ptr().getClass().isNpc())
|
||||
return sol::nil;
|
||||
|
||||
static std::optional<AIStat> create(ObjectVariant object, MWMechanics::AiSetting index)
|
||||
{
|
||||
if (!object.ptr().getClass().isActor())
|
||||
return {};
|
||||
return AIStat{ std::move(object), index };
|
||||
}
|
||||
return getValue(context, mObject, &setNpcValue, specialization, "skillIncreasesForSpecialization",
|
||||
[specialization](const MWWorld::Ptr& ptr) {
|
||||
return ptr.getClass().getNpcStats(ptr).getSkillIncreasesForSpecialization(
|
||||
static_cast<ESM::Class::Specialization>(specialization));
|
||||
});
|
||||
}
|
||||
|
||||
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{ &AIStat::setValue, static_cast<int>(mIndex), prop }]
|
||||
= sol::main_object(value);
|
||||
}
|
||||
void set(const Context& context, int specialization, const sol::object& value) const
|
||||
{
|
||||
const auto& ptr = mObject.ptr();
|
||||
if (!ptr.getClass().isNpc())
|
||||
return;
|
||||
|
||||
static void setValue(Index i, std::string_view prop, const MWWorld::Ptr& ptr, const sol::object& value)
|
||||
SelfObject* obj = mObject.asSelfObject();
|
||||
addStatUpdateAction(context.mLuaManager, *obj);
|
||||
obj->mStatsCache[SelfObject::CachedStat{
|
||||
&setNpcValue, specialization, "skillIncreasesForSpecialization" }]
|
||||
= sol::main_object(value);
|
||||
}
|
||||
};
|
||||
|
||||
class LevelStat
|
||||
{
|
||||
auto index = static_cast<MWMechanics::AiSetting>(std::get<int>(i));
|
||||
auto& stats = ptr.getClass().getCreatureStats(ptr);
|
||||
auto stat = stats.getAiSetting(index);
|
||||
int intValue = LuaUtil::cast<int>(value);
|
||||
if (prop == "base")
|
||||
stat.setBase(intValue);
|
||||
else if (prop == "modifier")
|
||||
stat.setModifier(intValue);
|
||||
stats.setAiSetting(index, stat);
|
||||
}
|
||||
};
|
||||
ObjectVariant mObject;
|
||||
|
||||
LevelStat(ObjectVariant object)
|
||||
: mObject(std::move(object))
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
sol::object getCurrent(const Context& context) const
|
||||
{
|
||||
return getValue(context, mObject, &setCreatureValue, std::monostate{}, "current",
|
||||
[](const MWWorld::Ptr& ptr) { return ptr.getClass().getCreatureStats(ptr).getLevel(); });
|
||||
}
|
||||
|
||||
void setCurrent(const Context& context, const sol::object& value) const
|
||||
{
|
||||
SelfObject* obj = mObject.asSelfObject();
|
||||
addStatUpdateAction(context.mLuaManager, *obj);
|
||||
obj->mStatsCache[SelfObject::CachedStat{ &setCreatureValue, std::monostate{}, "current" }]
|
||||
= sol::main_object(value);
|
||||
}
|
||||
|
||||
sol::object getProgress(const Context& context) const
|
||||
{
|
||||
if (!mObject.ptr().getClass().isNpc())
|
||||
return sol::nil;
|
||||
|
||||
return getValue(context, mObject, &setNpcValue, std::monostate{}, "progress",
|
||||
[](const MWWorld::Ptr& ptr) { return ptr.getClass().getNpcStats(ptr).getLevelProgress(); });
|
||||
}
|
||||
|
||||
void setProgress(const Context& context, const sol::object& value) const
|
||||
{
|
||||
const auto& ptr = mObject.ptr();
|
||||
if (!ptr.getClass().isNpc())
|
||||
return;
|
||||
|
||||
SelfObject* obj = mObject.asSelfObject();
|
||||
addStatUpdateAction(context.mLuaManager, *obj);
|
||||
obj->mStatsCache[SelfObject::CachedStat{ &setNpcValue, std::monostate{}, "progress" }]
|
||||
= sol::main_object(value);
|
||||
}
|
||||
|
||||
SkillIncreasesForAttributeStats getSkillIncreasesForAttributeStats() const
|
||||
{
|
||||
return SkillIncreasesForAttributeStats{ mObject };
|
||||
}
|
||||
|
||||
SkillIncreasesForSpecializationStats getSkillIncreasesForSpecializationStats() const
|
||||
{
|
||||
return SkillIncreasesForSpecializationStats{ mObject };
|
||||
}
|
||||
|
||||
static std::optional<LevelStat> create(ObjectVariant object, Index)
|
||||
{
|
||||
if (!object.ptr().getClass().isActor())
|
||||
return {};
|
||||
return LevelStat{ std::move(object) };
|
||||
}
|
||||
};
|
||||
|
||||
class DynamicStat
|
||||
{
|
||||
ObjectVariant mObject;
|
||||
int mIndex;
|
||||
|
||||
DynamicStat(ObjectVariant object, int index)
|
||||
: mObject(std::move(object))
|
||||
, mIndex(index)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
template <class G>
|
||||
sol::object get(const Context& context, std::string_view prop, G getter) const
|
||||
{
|
||||
return getValue(
|
||||
context, mObject, &DynamicStat::setValue, mIndex, prop, [this, getter](const MWWorld::Ptr& ptr) {
|
||||
return (ptr.getClass().getCreatureStats(ptr).getDynamic(mIndex).*getter)();
|
||||
});
|
||||
}
|
||||
|
||||
static std::optional<DynamicStat> create(ObjectVariant object, Index i)
|
||||
{
|
||||
if (!object.ptr().getClass().isActor())
|
||||
return {};
|
||||
int index = std::get<int>(i);
|
||||
return DynamicStat{ std::move(object), index };
|
||||
}
|
||||
|
||||
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{ &DynamicStat::setValue, mIndex, prop }]
|
||||
= sol::main_object(value);
|
||||
}
|
||||
|
||||
static void setValue(Index i, std::string_view prop, const MWWorld::Ptr& ptr, const sol::object& value)
|
||||
{
|
||||
int index = std::get<int>(i);
|
||||
auto& stats = ptr.getClass().getCreatureStats(ptr);
|
||||
auto stat = stats.getDynamic(index);
|
||||
float floatValue = LuaUtil::cast<float>(value);
|
||||
if (prop == "base")
|
||||
stat.setBase(floatValue);
|
||||
else if (prop == "current")
|
||||
stat.setCurrent(floatValue, true, true);
|
||||
else if (prop == "modifier")
|
||||
stat.setModifier(floatValue);
|
||||
stats.setDynamic(index, stat);
|
||||
}
|
||||
};
|
||||
|
||||
class AttributeStat
|
||||
{
|
||||
ObjectVariant mObject;
|
||||
ESM::RefId mId;
|
||||
|
||||
AttributeStat(ObjectVariant object, ESM::RefId id)
|
||||
: mObject(std::move(object))
|
||||
, mId(id)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
template <class G>
|
||||
sol::object get(const Context& context, std::string_view prop, G getter) const
|
||||
{
|
||||
return getValue(
|
||||
context, mObject, &AttributeStat::setValue, mId, prop, [this, getter](const MWWorld::Ptr& ptr) {
|
||||
return (ptr.getClass().getCreatureStats(ptr).getAttribute(mId).*getter)();
|
||||
});
|
||||
}
|
||||
|
||||
float getModified(const Context& context) const
|
||||
{
|
||||
auto base = LuaUtil::cast<float>(get(context, "base", &MWMechanics::AttributeValue::getBase));
|
||||
auto damage = LuaUtil::cast<float>(get(context, "damage", &MWMechanics::AttributeValue::getDamage));
|
||||
auto modifier
|
||||
= LuaUtil::cast<float>(get(context, "modifier", &MWMechanics::AttributeValue::getModifier));
|
||||
return std::max(0.f, base - damage + modifier); // Should match AttributeValue::getModified
|
||||
}
|
||||
|
||||
static std::optional<AttributeStat> create(ObjectVariant object, Index i)
|
||||
{
|
||||
if (!object.ptr().getClass().isActor())
|
||||
return {};
|
||||
ESM::RefId id = std::get<ESM::RefId>(i);
|
||||
return AttributeStat{ 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{ &AttributeStat::setValue, mId, prop }]
|
||||
= sol::main_object(value);
|
||||
}
|
||||
|
||||
static void setValue(Index i, std::string_view prop, const MWWorld::Ptr& ptr, const sol::object& value)
|
||||
{
|
||||
ESM::RefId id = std::get<ESM::RefId>(i);
|
||||
auto& stats = ptr.getClass().getCreatureStats(ptr);
|
||||
auto stat = stats.getAttribute(id);
|
||||
float floatValue = LuaUtil::cast<float>(value);
|
||||
if (prop == "base")
|
||||
stat.setBase(floatValue);
|
||||
else if (prop == "damage")
|
||||
{
|
||||
stat.restore(stat.getDamage());
|
||||
stat.damage(floatValue);
|
||||
}
|
||||
else if (prop == "modifier")
|
||||
stat.setModifier(floatValue);
|
||||
stats.setAttribute(id, stat);
|
||||
}
|
||||
};
|
||||
|
||||
class SkillStat
|
||||
{
|
||||
ObjectVariant mObject;
|
||||
ESM::RefId mId;
|
||||
|
||||
SkillStat(ObjectVariant object, ESM::RefId id)
|
||||
: mObject(std::move(object))
|
||||
, mId(id)
|
||||
{
|
||||
}
|
||||
|
||||
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, id, stat);
|
||||
return progress;
|
||||
}
|
||||
|
||||
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(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, mId, prop, [this, getter](const MWWorld::Ptr& ptr) {
|
||||
return (ptr.getClass().getNpcStats(ptr).getSkill(mId).*getter)();
|
||||
});
|
||||
}
|
||||
|
||||
float getModified(const Context& context) const
|
||||
{
|
||||
auto base = LuaUtil::cast<float>(get(context, "base", &MWMechanics::SkillValue::getBase));
|
||||
auto damage = LuaUtil::cast<float>(get(context, "damage", &MWMechanics::SkillValue::getDamage));
|
||||
auto modifier = LuaUtil::cast<float>(get(context, "modifier", &MWMechanics::SkillValue::getModifier));
|
||||
return std::max(0.f, base - damage + modifier); // Should match SkillValue::getModified
|
||||
}
|
||||
|
||||
sol::object getProgress(const Context& context) const
|
||||
{
|
||||
return getValue(
|
||||
context, mObject, &SkillStat::setValue, mId, "progress", [this](const MWWorld::Ptr& ptr) {
|
||||
return getProgress(ptr, mId, ptr.getClass().getNpcStats(ptr).getSkill(mId));
|
||||
});
|
||||
}
|
||||
|
||||
static std::optional<SkillStat> create(ObjectVariant object, Index index)
|
||||
{
|
||||
if (!object.ptr().getClass().isNpc())
|
||||
return {};
|
||||
ESM::RefId id = std::get<ESM::RefId>(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, mId, prop }] = sol::main_object(value);
|
||||
}
|
||||
|
||||
static void setValue(Index index, std::string_view prop, const MWWorld::Ptr& ptr, const sol::object& value)
|
||||
{
|
||||
ESM::RefId id = std::get<ESM::RefId>(index);
|
||||
auto& stats = ptr.getClass().getNpcStats(ptr);
|
||||
auto stat = stats.getSkill(id);
|
||||
float floatValue = LuaUtil::cast<float>(value);
|
||||
if (prop == "base")
|
||||
stat.setBase(floatValue);
|
||||
else if (prop == "damage")
|
||||
{
|
||||
stat.restore(stat.getDamage());
|
||||
stat.damage(floatValue);
|
||||
}
|
||||
else if (prop == "modifier")
|
||||
stat.setModifier(floatValue);
|
||||
else if (prop == "progress")
|
||||
stat.setProgress(floatValue * getMaxProgress(ptr, id, stat));
|
||||
stats.setSkill(id, stat);
|
||||
}
|
||||
};
|
||||
|
||||
class AIStat
|
||||
{
|
||||
ObjectVariant mObject;
|
||||
MWMechanics::AiSetting mIndex;
|
||||
|
||||
AIStat(ObjectVariant object, MWMechanics::AiSetting index)
|
||||
: mObject(std::move(object))
|
||||
, mIndex(index)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
template <class G>
|
||||
sol::object get(const Context& context, std::string_view prop, G getter) const
|
||||
{
|
||||
return getValue(context, mObject, &AIStat::setValue, static_cast<int>(mIndex), prop,
|
||||
[this, getter](const MWWorld::Ptr& ptr) {
|
||||
return (ptr.getClass().getCreatureStats(ptr).getAiSetting(mIndex).*getter)();
|
||||
});
|
||||
}
|
||||
|
||||
int getModified(const Context& context) const
|
||||
{
|
||||
auto base = LuaUtil::cast<int>(get(context, "base", &MWMechanics::Stat<int>::getBase));
|
||||
auto modifier = LuaUtil::cast<int>(get(context, "modifier", &MWMechanics::Stat<int>::getModifier));
|
||||
return std::max(0, base + modifier);
|
||||
}
|
||||
|
||||
static std::optional<AIStat> create(ObjectVariant object, MWMechanics::AiSetting index)
|
||||
{
|
||||
if (!object.ptr().getClass().isActor())
|
||||
return {};
|
||||
return AIStat{ std::move(object), index };
|
||||
}
|
||||
|
||||
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{ &AIStat::setValue, static_cast<int>(mIndex), prop }]
|
||||
= sol::main_object(value);
|
||||
}
|
||||
|
||||
static void setValue(Index i, std::string_view prop, const MWWorld::Ptr& ptr, const sol::object& value)
|
||||
{
|
||||
auto index = static_cast<MWMechanics::AiSetting>(std::get<int>(i));
|
||||
auto& stats = ptr.getClass().getCreatureStats(ptr);
|
||||
auto stat = stats.getAiSetting(index);
|
||||
int intValue = LuaUtil::cast<int>(value);
|
||||
if (prop == "base")
|
||||
stat.setBase(intValue);
|
||||
else if (prop == "modifier")
|
||||
stat.setModifier(intValue);
|
||||
stats.setAiSetting(index, stat);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
namespace sol
|
||||
|
|
|
|||
Loading…
Reference in a new issue