1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-04-09 21:44:54 +00:00

Lua stats

This commit is contained in:
Evil Eye 2022-03-25 20:03:13 +00:00 committed by Petr Mikheev
parent 1542a0392c
commit 93d195646c
13 changed files with 732 additions and 4 deletions

View File

@ -59,8 +59,8 @@ add_openmw_dir (mwscript
add_openmw_dir (mwlua add_openmw_dir (mwlua
luamanagerimp actions object worldview userdataserializer eventqueue luamanagerimp actions object worldview userdataserializer eventqueue
luabindings localscripts playerscripts objectbindings cellbindings asyncbindings settingsbindings luabindings localscripts playerscripts objectbindings cellbindings asyncbindings settingsbindings
camerabindings uibindings inputbindings nearbybindings camerabindings uibindings inputbindings nearbybindings stats
types/types types/door types/actor types/container types/weapon types/types types/door types/actor types/container types/weapon types/npc
) )
add_openmw_dir (mwsound add_openmw_dir (mwsound

View File

@ -1,5 +1,7 @@
#include "actions.hpp" #include "actions.hpp"
#include "localscripts.hpp"
#include <cstring> #include <cstring>
#include <components/debug/debuglog.hpp> #include <components/debug/debuglog.hpp>
@ -168,4 +170,11 @@ namespace MWLua
std::string(" actor=") + idToString(mActor); std::string(" actor=") + idToString(mActor);
} }
void StatUpdateAction::apply(WorldView& worldView) const
{
LObject obj(mId, worldView.getObjectRegistry());
LocalScripts* scripts = obj.ptr().getRefData().getLuaScripts();
if (scripts)
scripts->applyStatsCache();
}
} }

View File

@ -79,6 +79,16 @@ namespace MWLua
ObjectId mActor; ObjectId mActor;
}; };
class StatUpdateAction final : public Action
{
ObjectId mId;
public:
StatUpdateAction(LuaUtil::LuaState* state, ObjectId id) : Action(state), mId(id) {}
void apply(WorldView& worldView) const override;
std::string toString() const override { return "StatUpdateAction"; }
};
} }
#endif // MWLUA_ACTIONS_H #endif // MWLUA_ACTIONS_H

View File

@ -182,4 +182,11 @@ namespace MWLua
}, event); }, event);
} }
void LocalScripts::applyStatsCache()
{
const auto& ptr = mData.ptr();
for (auto& [stat, value] : mData.mStatsCache)
stat(ptr, value);
mData.mStatsCache.clear();
}
} }

View File

@ -26,8 +26,31 @@ namespace MWLua
struct SelfObject : public LObject struct SelfObject : public LObject
{ {
class CachedStat
{
public:
using Setter = void(*)(int, std::string_view, const MWWorld::Ptr&, const sol::object&);
private:
Setter mSetter; // Function that updates a stat's property
int mIndex; // Optional index to disambiguate the stat
std::string_view mProp; // Name of the stat's property
public:
CachedStat(Setter setter, int index, std::string_view prop) : mSetter(setter), mIndex(index), mProp(std::move(prop)) {}
void operator()(const MWWorld::Ptr& ptr, const sol::object& object) const
{
mSetter(mIndex, mProp, ptr, object);
}
bool operator<(const CachedStat& other) const
{
return std::tie(mSetter, mIndex, mProp) < std::tie(other.mSetter, other.mIndex, other.mProp);
}
};
SelfObject(const LObject& obj) : LObject(obj), mIsActive(false) {} SelfObject(const LObject& obj) : LObject(obj), mIsActive(false) {}
MWBase::LuaManager::ActorControls mControls; MWBase::LuaManager::ActorControls mControls;
std::map<CachedStat, sol::object> mStatsCache;
bool mIsActive; bool mIsActive;
}; };
@ -45,6 +68,7 @@ namespace MWLua
void receiveEngineEvent(const EngineEvent&); void receiveEngineEvent(const EngineEvent&);
void applyStatsCache();
protected: protected:
SelfObject mData; SelfObject mData;

View File

@ -41,7 +41,7 @@ namespace MWLua
{ {
auto* lua = context.mLua; auto* lua = context.mLua;
sol::table api(lua->sol(), sol::create); sol::table api(lua->sol(), sol::create);
api["API_REVISION"] = 18; api["API_REVISION"] = 19;
api["quit"] = [lua]() api["quit"] = [lua]()
{ {
Log(Debug::Warning) << "Quit requested by a Lua script.\n" << lua->debugTraceback(); Log(Debug::Warning) << "Quit requested by a Lua script.\n" << lua->debugTraceback();

369
apps/openmw/mwlua/stats.cpp Normal file
View File

@ -0,0 +1,369 @@
#include "stats.hpp"
#include <memory>
#include <optional>
#include <string_view>
#include <variant>
#include <components/lua/luastate.hpp>
#include <components/misc/stringops.hpp>
#include "localscripts.hpp"
#include "luamanagerimp.hpp"
#include "../mwmechanics/creaturestats.hpp"
#include "../mwmechanics/npcstats.hpp"
#include "../mwworld/class.hpp"
#include "../mwworld/esmstore.hpp"
namespace
{
template<class T>
auto addIndexedAccessor(int index)
{
return sol::overload(
[index](MWLua::LocalScripts::SelfObject& o) { return T::create(&o, index); },
[index](const MWLua::LObject& o) { return T::create(o, index); },
[index](const MWLua::GObject& o) { return T::create(o, index); }
);
}
template<class T, class G>
void addProp(const MWLua::Context& context, sol::usertype<T>& type, std::string_view prop, G getter, bool readOnly = false)
{
if(readOnly)
type[prop] = sol::property([=](const T& stat) { return stat.get(context, prop, getter); });
else
type[prop] = sol::property(
[=](const T& stat) { return stat.get(context, prop, getter); },
[=](const T& stat, const sol::object& value) { stat.cache(context, prop, value); });
}
using SelfObject = MWLua::LocalScripts::SelfObject;
using StatObject = std::variant<SelfObject*, MWLua::LObject, MWLua::GObject>;
const MWLua::Object* getObject(const StatObject& obj)
{
return std::visit([] (auto&& variant) -> const MWLua::Object*
{
using T = std::decay_t<decltype(variant)>;
if constexpr(std::is_same_v<T, SelfObject*>)
return variant;
else if constexpr(std::is_same_v<T, MWLua::LObject>)
return &variant;
else if constexpr(std::is_same_v<T, MWLua::GObject>)
return &variant;
}, obj);
}
template<class G>
sol::object getValue(const MWLua::Context& context, const StatObject& obj, SelfObject::CachedStat::Setter setter, int index, std::string_view prop, G getter)
{
return std::visit([&] (auto&& variant)
{
using T = std::decay_t<decltype(variant)>;
if constexpr(std::is_same_v<T, SelfObject*>)
{
auto it = variant->mStatsCache.find({ setter, index, prop });
if(it != variant->mStatsCache.end())
return it->second;
return sol::make_object(context.mLua->sol(), getter(variant));
}
else if constexpr(std::is_same_v<T, MWLua::LObject>)
return sol::make_object(context.mLua->sol(), getter(&variant));
else if constexpr(std::is_same_v<T, MWLua::GObject>)
return sol::make_object(context.mLua->sol(), getter(&variant));
}, obj);
}
}
namespace MWLua
{
class LevelStat
{
StatObject mObject;
LevelStat(StatObject object) : mObject(std::move(object)) {}
public:
sol::object getCurrent(const Context& context) const
{
return getValue(context, mObject, &LevelStat::setValue, 0, "current", [](const MWLua::Object* obj)
{
const auto& ptr = obj->ptr();
return ptr.getClass().getCreatureStats(ptr).getLevel();
});
}
void setCurrent(const Context& context, const sol::object& value) const
{
SelfObject* obj = std::get<SelfObject*>(mObject);
if(obj->mStatsCache.empty())
context.mLuaManager->addAction(std::make_unique<StatUpdateAction>(context.mLua, obj->id()));
obj->mStatsCache[SelfObject::CachedStat{&LevelStat::setValue, 0, "current"}] = value;
}
sol::object getProgress(const Context& context) const
{
const auto& ptr = getObject(mObject)->ptr();
if(!ptr.getClass().isNpc())
return sol::nil;
return sol::make_object(context.mLua->sol(), ptr.getClass().getNpcStats(ptr).getLevelProgress());
}
static std::optional<LevelStat> create(StatObject object, int index)
{
if(!getObject(object)->ptr().getClass().isActor())
return {};
return LevelStat{std::move(object)};
}
static void setValue(int, std::string_view prop, const MWWorld::Ptr& ptr, const sol::object& value)
{
auto& stats = ptr.getClass().getCreatureStats(ptr);
if(prop == "current")
stats.setLevel(value.as<int>());
}
};
class DynamicStat
{
StatObject mObject;
int mIndex;
DynamicStat(StatObject 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, [=](const MWLua::Object* obj)
{
const auto& ptr = obj->ptr();
return (ptr.getClass().getCreatureStats(ptr).getDynamic(mIndex).*getter)();
});
}
static std::optional<DynamicStat> create(StatObject object, int index)
{
if(!getObject(object)->ptr().getClass().isActor())
return {};
return DynamicStat{std::move(object), index};
}
void cache(const Context& context, std::string_view prop, const sol::object& value) const
{
SelfObject* obj = std::get<SelfObject*>(mObject);
if(obj->mStatsCache.empty())
context.mLuaManager->addAction(std::make_unique<StatUpdateAction>(context.mLua, obj->id()));
obj->mStatsCache[SelfObject::CachedStat{&DynamicStat::setValue, mIndex, prop}] = value;
}
static void setValue(int index, std::string_view prop, const MWWorld::Ptr& ptr, const sol::object& value)
{
auto& stats = ptr.getClass().getCreatureStats(ptr);
auto stat = stats.getDynamic(index);
float floatValue = value.as<float>();
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
{
StatObject mObject;
int mIndex;
AttributeStat(StatObject 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, &AttributeStat::setValue, mIndex, prop, [=](const MWLua::Object* obj)
{
const auto& ptr = obj->ptr();
return (ptr.getClass().getCreatureStats(ptr).getAttribute(mIndex).*getter)();
});
}
static std::optional<AttributeStat> create(StatObject object, int index)
{
if(!getObject(object)->ptr().getClass().isActor())
return {};
return AttributeStat{std::move(object), index};
}
void cache(const Context& context, std::string_view prop, const sol::object& value) const
{
SelfObject* obj = std::get<SelfObject*>(mObject);
if(obj->mStatsCache.empty())
context.mLuaManager->addAction(std::make_unique<StatUpdateAction>(context.mLua, obj->id()));
obj->mStatsCache[SelfObject::CachedStat{&AttributeStat::setValue, mIndex, prop}] = value;
}
static void setValue(int index, std::string_view prop, const MWWorld::Ptr& ptr, const sol::object& value)
{
auto& stats = ptr.getClass().getCreatureStats(ptr);
auto stat = stats.getAttribute(index);
float floatValue = value.as<float>();
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(index, stat);
}
};
class SkillStat
{
StatObject mObject;
int mIndex;
SkillStat(StatObject object, int index) : mObject(std::move(object)), mIndex(index) {}
static float getProgress(const MWWorld::Ptr& ptr, int index, const MWMechanics::SkillValue& stat)
{
float progress = stat.getProgress();
if(progress != 0.f)
progress /= getMaxProgress(ptr, index, stat);
return progress;
}
static float getMaxProgress(const MWWorld::Ptr& ptr, int index, const MWMechanics::SkillValue& stat) {
const auto& store = MWBase::Environment::get().getWorld()->getStore();
const auto cl = store.get<ESM::Class>().find(ptr.get<ESM::NPC>()->mBase->mClass);
return ptr.getClass().getNpcStats(ptr).getSkillProgressRequirement(index, *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, [=](const MWLua::Object* obj)
{
const auto& ptr = obj->ptr();
return (ptr.getClass().getNpcStats(ptr).getSkill(mIndex).*getter)();
});
}
sol::object getProgress(const Context& context) const
{
return getValue(context, mObject, &SkillStat::setValue, mIndex, "progress", [=](const MWLua::Object* obj)
{
const auto& ptr = obj->ptr();
return getProgress(ptr, mIndex, ptr.getClass().getNpcStats(ptr).getSkill(mIndex));
});
}
static std::optional<SkillStat> create(StatObject object, int index)
{
if(!getObject(object)->ptr().getClass().isNpc())
return {};
return SkillStat{std::move(object), index};
}
void cache(const Context& context, std::string_view prop, const sol::object& value) const
{
SelfObject* obj = std::get<SelfObject*>(mObject);
if(obj->mStatsCache.empty())
context.mLuaManager->addAction(std::make_unique<StatUpdateAction>(context.mLua, obj->id()));
obj->mStatsCache[SelfObject::CachedStat{&SkillStat::setValue, mIndex, prop}] = value;
}
static void setValue(int index, std::string_view prop, const MWWorld::Ptr& ptr, const sol::object& value)
{
auto& stats = ptr.getClass().getNpcStats(ptr);
auto stat = stats.getSkill(index);
float floatValue = value.as<float>();
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, index, stat));
stats.setSkill(index, stat);
}
};
}
namespace sol
{
template <>
struct is_automagical<MWLua::LevelStat> : std::false_type {};
template <>
struct is_automagical<MWLua::DynamicStat> : std::false_type {};
template <>
struct is_automagical<MWLua::AttributeStat> : std::false_type {};
template <>
struct is_automagical<MWLua::SkillStat> : std::false_type {};
}
namespace MWLua
{
void addActorStatsBindings(sol::table& actor, const Context& context)
{
sol::table stats(context.mLua->sol(), sol::create);
actor["stats"] = LuaUtil::makeReadOnly(stats);
auto levelStatT = context.mLua->sol().new_usertype<LevelStat>("LevelStat");
levelStatT["current"] = sol::property(
[context](const LevelStat& stat) { return stat.getCurrent(context); },
[context](const LevelStat& stat, const sol::object& value) { stat.setCurrent(context, value); });
levelStatT["progress"] = sol::property([context](const LevelStat& stat) { return stat.getProgress(context); });
stats["level"] = addIndexedAccessor<LevelStat>(0);
auto dynamicStatT = context.mLua->sol().new_usertype<DynamicStat>("DynamicStat");
addProp(context, dynamicStatT, "base", &MWMechanics::DynamicStat<float>::getBase);
addProp(context, dynamicStatT, "current", &MWMechanics::DynamicStat<float>::getCurrent);
addProp(context, dynamicStatT, "modifier", &MWMechanics::DynamicStat<float>::getModifier);
sol::table dynamic(context.mLua->sol(), sol::create);
stats["dynamic"] = LuaUtil::makeReadOnly(dynamic);
dynamic["health"] = addIndexedAccessor<DynamicStat>(0);
dynamic["magicka"] = addIndexedAccessor<DynamicStat>(1);
dynamic["fatigue"] = addIndexedAccessor<DynamicStat>(2);
auto attributeStatT = context.mLua->sol().new_usertype<AttributeStat>("AttributeStat");
addProp(context, attributeStatT, "base", &MWMechanics::AttributeValue::getBase);
addProp(context, attributeStatT, "damage", &MWMechanics::AttributeValue::getDamage);
addProp(context, attributeStatT, "modified", &MWMechanics::AttributeValue::getModified, true);
addProp(context, attributeStatT, "modifier", &MWMechanics::AttributeValue::getModifier);
sol::table attributes(context.mLua->sol(), sol::create);
stats["attributes"] = LuaUtil::makeReadOnly(attributes);
for(int id = ESM::Attribute::Strength; id < ESM::Attribute::Length; ++id)
attributes[Misc::StringUtils::lowerCase(ESM::Attribute::sAttributeNames[id])] = addIndexedAccessor<AttributeStat>(id);
}
void addNpcStatsBindings(sol::table& npc, const Context& context)
{
sol::table npcStats(context.mLua->sol(), sol::create);
sol::table baseMeta(context.mLua->sol(), sol::create);
baseMeta[sol::meta_function::index] = LuaUtil::getMutableFromReadOnly(npc["baseType"]["stats"]);
npcStats[sol::metatable_key] = baseMeta;
npc["stats"] = LuaUtil::makeReadOnly(npcStats);
auto skillStatT = context.mLua->sol().new_usertype<SkillStat>("SkillStat");
addProp(context, skillStatT, "base", &MWMechanics::SkillValue::getBase);
addProp(context, skillStatT, "damage", &MWMechanics::SkillValue::getDamage);
addProp(context, skillStatT, "modified", &MWMechanics::SkillValue::getModified, true);
addProp(context, skillStatT, "modifier", &MWMechanics::SkillValue::getModifier);
skillStatT["progress"] = sol::property(
[context](const SkillStat& stat) { return stat.getProgress(context); },
[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);
}
}

View File

@ -0,0 +1,12 @@
#ifndef MWLUA_STATS_H
#define MWLUA_STATS_H
#include "context.hpp"
namespace MWLua
{
void addActorStatsBindings(sol::table& actor, const Context& context);
void addNpcStatsBindings(sol::table& npc, const Context& context);
}
#endif

View File

@ -10,6 +10,7 @@
#include "../luabindings.hpp" #include "../luabindings.hpp"
#include "../localscripts.hpp" #include "../localscripts.hpp"
#include "../luamanagerimp.hpp" #include "../luamanagerimp.hpp"
#include "../stats.hpp"
namespace MWLua namespace MWLua
{ {
@ -132,6 +133,8 @@ namespace MWLua
} }
context.mLuaManager->addAction(std::make_unique<SetEquipmentAction>(context.mLua, obj.id(), std::move(eqp))); context.mLuaManager->addAction(std::make_unique<SetEquipmentAction>(context.mLua, obj.id(), std::move(eqp)));
}; };
addActorStatsBindings(actor, context);
} }
} }

View File

@ -0,0 +1,11 @@
#include "types.hpp"
#include "../stats.hpp"
namespace MWLua
{
void addNpcBindings(sol::table npc, const Context& context)
{
addNpcStatsBindings(npc, context);
}
}

View File

@ -156,7 +156,7 @@ namespace MWLua
ESM::REC_APPA, ESM::REC_LOCK, ESM::REC_PROB, ESM::REC_REPA}); ESM::REC_APPA, ESM::REC_LOCK, ESM::REC_PROB, ESM::REC_REPA});
addType(ObjectTypeName::Creature, {ESM::REC_CREA}, ObjectTypeName::Actor); addType(ObjectTypeName::Creature, {ESM::REC_CREA}, ObjectTypeName::Actor);
addType(ObjectTypeName::NPC, {ESM::REC_INTERNAL_PLAYER, ESM::REC_NPC_}, ObjectTypeName::Actor); addNpcBindings(addType(ObjectTypeName::NPC, {ESM::REC_INTERNAL_PLAYER, ESM::REC_NPC_}, ObjectTypeName::Actor), context);
addType(ObjectTypeName::Player, {ESM::REC_INTERNAL_PLAYER}, ObjectTypeName::NPC); addType(ObjectTypeName::Player, {ESM::REC_INTERNAL_PLAYER}, ObjectTypeName::NPC);
addType(ObjectTypeName::Armor, {ESM::REC_ARMO}, ObjectTypeName::Item); addType(ObjectTypeName::Armor, {ESM::REC_ARMO}, ObjectTypeName::Item);

View File

@ -28,6 +28,7 @@ namespace MWLua
void addDoorBindings(sol::table door, const Context& context); void addDoorBindings(sol::table door, const Context& context);
void addActorBindings(sol::table actor, const Context& context); void addActorBindings(sol::table actor, const Context& context);
void addWeaponBindings(sol::table weapon, const Context& context); void addWeaponBindings(sol::table weapon, const Context& context);
void addNpcBindings(sol::table npc, const Context& context);
} }
#endif // MWLUA_TYPES_H #endif // MWLUA_TYPES_H

View File

@ -128,6 +128,287 @@
-- local Actor = require('openmw.types').Actor -- local Actor = require('openmw.types').Actor
-- Actor.setEquipment(self, {}) -- unequip all -- Actor.setEquipment(self, {}) -- unequip all
---
-- @type LevelStat
-- @field #number current The actor's current level.
-- @field #number progress The NPC's level progress (read-only.)
---
-- @type DynamicStat
-- @field #number base
-- @field #number current
-- @field #number modifier
---
-- @type AttributeStat
-- @field #number base The actor's base attribute value.
-- @field #number damage The amount the attribute has been damaged.
-- @field #number modified The actor's current attribute value (read-only.)
-- @field #number modifier The attribute's modifier.
---
-- @type SkillStat
-- @field #number base The NPC's base skill value.
-- @field #number damage The amount the skill has been damaged.
-- @field #number modified The NPC's current skill value (read-only.)
-- @field #number modifier The skill's modifier.
-- @field #number progress [0-1] The NPC's skill progress.
---
-- @type DynamicStats
---
-- Health (returns @{#DynamicStat})
-- @function [parent=#DynamicStats] health
-- @param openmw.core#GameObject actor
-- @return #DynamicStat
---
-- Magicka (returns @{#DynamicStat})
-- @function [parent=#DynamicStats] magicka
-- @param openmw.core#GameObject actor
-- @return #DynamicStat
---
-- Fatigue (returns @{#DynamicStat})
-- @function [parent=#DynamicStats] fatigue
-- @param openmw.core#GameObject actor
-- @return #DynamicStat
---
-- @type AttributeStats
---
-- Strength (returns @{#AttributeStat})
-- @function [parent=#AttributeStats] strength
-- @param openmw.core#GameObject actor
-- @return #AttributeStat
---
-- Intelligence (returns @{#AttributeStat})
-- @function [parent=#AttributeStats] intelligence
-- @param openmw.core#GameObject actor
-- @return #AttributeStat
---
-- Willpower (returns @{#AttributeStat})
-- @function [parent=#AttributeStats] willpower
-- @param openmw.core#GameObject actor
-- @return #AttributeStat
---
-- Agility (returns @{#AttributeStat})
-- @function [parent=#AttributeStats] agility
-- @param openmw.core#GameObject actor
-- @return #AttributeStat
---
-- Speed (returns @{#AttributeStat})
-- @function [parent=#AttributeStats] speed
-- @param openmw.core#GameObject actor
-- @return #AttributeStat
---
-- Endurance (returns @{#AttributeStat})
-- @function [parent=#AttributeStats] endurance
-- @param openmw.core#GameObject actor
-- @return #AttributeStat
---
-- Personality (returns @{#AttributeStat})
-- @function [parent=#AttributeStats] personality
-- @param openmw.core#GameObject actor
-- @return #AttributeStat
---
-- Luck (returns @{#AttributeStat})
-- @function [parent=#AttributeStats] luck
-- @param openmw.core#GameObject actor
-- @return #AttributeStat
---
-- @type SkillStats
---
-- Block (returns @{#SkillStat})
-- @function [parent=#SkillStats] block
-- @param openmw.core#GameObject actor
-- @return #SkillStat
---
-- Armorer (returns @{#SkillStat})
-- @function [parent=#SkillStats] armorer
-- @param openmw.core#GameObject actor
-- @return #SkillStat
---
-- Medium Armor (returns @{#SkillStat})
-- @function [parent=#SkillStats] mediumarmor
-- @param openmw.core#GameObject actor
-- @return #SkillStat
---
-- Heavy Armor (returns @{#SkillStat})
-- @function [parent=#SkillStats] heavyarmor
-- @param openmw.core#GameObject actor
-- @return #SkillStat
---
-- Blunt Weapon (returns @{#SkillStat})
-- @function [parent=#SkillStats] bluntweapon
-- @param openmw.core#GameObject actor
-- @return #SkillStat
---
-- Long Blade (returns @{#SkillStat})
-- @function [parent=#SkillStats] longblade
-- @param openmw.core#GameObject actor
-- @return #SkillStat
---
-- Axe (returns @{#SkillStat})
-- @function [parent=#SkillStats] axe
-- @param openmw.core#GameObject actor
-- @return #SkillStat
---
-- Spear (returns @{#SkillStat})
-- @function [parent=#SkillStats] spear
-- @param openmw.core#GameObject actor
-- @return #SkillStat
---
-- Athletics (returns @{#SkillStat})
-- @function [parent=#SkillStats] athletics
-- @param openmw.core#GameObject actor
-- @return #SkillStat
---
-- Enchant (returns @{#SkillStat})
-- @function [parent=#SkillStats] enchant
-- @param openmw.core#GameObject actor
-- @return #SkillStat
---
-- Destruction (returns @{#SkillStat})
-- @function [parent=#SkillStats] destruction
-- @param openmw.core#GameObject actor
-- @return #SkillStat
---
-- Alteration (returns @{#SkillStat})
-- @function [parent=#SkillStats] alteration
-- @param openmw.core#GameObject actor
-- @return #SkillStat
---
-- Illusion (returns @{#SkillStat})
-- @function [parent=#SkillStats] illusion
-- @param openmw.core#GameObject actor
-- @return #SkillStat
---
-- Conjuration (returns @{#SkillStat})
-- @function [parent=#SkillStats] conjuration
-- @param openmw.core#GameObject actor
-- @return #SkillStat
---
-- Mysticism (returns @{#SkillStat})
-- @function [parent=#SkillStats] mysticism
-- @param openmw.core#GameObject actor
-- @return #SkillStat
---
-- Restoration (returns @{#SkillStat})
-- @function [parent=#SkillStats] restoration
-- @param openmw.core#GameObject actor
-- @return #SkillStat
---
-- Alchemy (returns @{#SkillStat})
-- @function [parent=#SkillStats] alchemy
-- @param openmw.core#GameObject actor
-- @return #SkillStat
---
-- Unarmored (returns @{#SkillStat})
-- @function [parent=#SkillStats] unarmored
-- @param openmw.core#GameObject actor
-- @return #SkillStat
---
-- Security (returns @{#SkillStat})
-- @function [parent=#SkillStats] security
-- @param openmw.core#GameObject actor
-- @return #SkillStat
---
-- Sneak (returns @{#SkillStat})
-- @function [parent=#SkillStats] sneak
-- @param openmw.core#GameObject actor
-- @return #SkillStat
---
-- Acrobatics (returns @{#SkillStat})
-- @function [parent=#SkillStats] acrobatics
-- @param openmw.core#GameObject actor
-- @return #SkillStat
---
-- Light Armor (returns @{#SkillStat})
-- @function [parent=#SkillStats] lightarmor
-- @param openmw.core#GameObject actor
-- @return #SkillStat
---
-- Short Blade (returns @{#SkillStat})
-- @function [parent=#SkillStats] shortblade
-- @param openmw.core#GameObject actor
-- @return #SkillStat
---
-- Marksman (returns @{#SkillStat})
-- @function [parent=#SkillStats] marksman
-- @param openmw.core#GameObject actor
-- @return #SkillStat
---
-- Mercantile (returns @{#SkillStat})
-- @function [parent=#SkillStats] mercantile
-- @param openmw.core#GameObject actor
-- @return #SkillStat
---
-- Speechcraft (returns @{#SkillStat})
-- @function [parent=#SkillStats] speechcraft
-- @param openmw.core#GameObject actor
-- @return #SkillStat
---
-- Hand To Hand (returns @{#SkillStat})
-- @function [parent=#SkillStats] handtohand
-- @param openmw.core#GameObject actor
-- @return #SkillStat
---
-- @type ActorStats
-- @field #DynamicStats dynamic
-- @field #AttributeStats attributes
---
-- Level (returns @{#LevelStat})
-- @function [parent=#ActorStats] level
-- @param openmw.core#GameObject actor
-- @return #LevelStat
--- The actor's stats.
-- @field [parent=#Actor] #ActorStats stats
---
-- @type NpcStats
-- @extends ActorStats
-- @field #SkillStats skills
--- @{#Item} functions (all pickable items that can be placed to an inventory or container) --- @{#Item} functions (all pickable items that can be placed to an inventory or container)
@ -167,6 +448,7 @@
-- @type NPC -- @type NPC
-- @extends #Actor -- @extends #Actor
-- @field #Actor baseType @{#Actor} -- @field #Actor baseType @{#Actor}
-- @field [parent=#NPC] #NpcStats stats
--- ---
-- Whether the object is an NPC or a Player. -- Whether the object is an NPC or a Player.