1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-01-20 02:53:53 +00:00
This commit is contained in:
Kindi 2023-09-15 23:26:58 +08:00
parent ff16ee2d64
commit 83ebaf27cc
7 changed files with 153 additions and 82 deletions

View file

@ -61,8 +61,8 @@ add_openmw_dir (mwscript
add_openmw_dir (mwlua add_openmw_dir (mwlua
luamanagerimp object objectlists userdataserializer luaevents engineevents objectvariant luamanagerimp object objectlists userdataserializer luaevents engineevents objectvariant
context globalscripts localscripts playerscripts luabindings objectbindings cellbindings mwscriptbindings context globalscripts localscripts playerscripts luabindings objectbindings cellbindings mwscriptbindings
camerabindings vfsbindings uibindings soundbindings inputbindings nearbybindings postprocessingbindings stats debugbindings camerabindings vfsbindings uibindings soundbindings inputbindings nearbybindings postprocessingbindings stats debugbindings itemdata
types/types types/door types/item types/actor types/container types/lockable types/weapon types/npc types/creature types/player types/activator types/book types/lockpick types/probe types/apparatus types/potion types/ingredient types/misc types/repair types/armor types/light types/static types/clothing types/levelledlist types/terminal types/itemstats types/types types/door types/item types/actor types/container types/lockable types/weapon types/npc types/creature types/player types/activator types/book types/lockpick types/probe types/apparatus types/potion types/ingredient types/misc types/repair types/armor types/light types/static types/clothing types/levelledlist types/terminal
worker magicbindings factionbindings worker magicbindings factionbindings
) )

View file

@ -0,0 +1,129 @@
#include "itemdata.hpp"
#include "context.hpp"
#include "luamanagerimp.hpp"
#include "../mwworld/class.hpp"
#include "objectvariant.hpp"
namespace
{
using SelfObject = MWLua::SelfObject;
using Index = const SelfObject::CachedStat::Index&;
constexpr std::array properties = { "condition", /*"enchantmentCharge", "soul", "owner", etc..*/ };
void invalidPropErr(std::string_view prop, const MWWorld::Ptr& ptr)
{
throw std::runtime_error(std::string(prop) + " does not exist for item "
+ std::string(ptr.getClass().getName(ptr)) + "(" + std::string(ptr.getTypeDescription()) + ")");
}
}
namespace MWLua
{
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");
}
class ItemData
{
ObjectVariant mObject;
public:
ItemData(ObjectVariant object)
: mObject(object)
{
}
sol::object get(const Context& context, std::string_view prop) const
{
if (mObject.isSelfObject())
{
SelfObject* self = mObject.asSelfObject();
auto it = self->mStatsCache.find({ &ItemData::setValue, std::monostate{}, prop });
if (it != self->mStatsCache.end())
return it->second;
}
return sol::make_object(context.mLua->sol(), getValue(context, prop));
}
void set(const Context& context, std::string_view prop, const sol::object& value) const
{
SelfObject* obj = mObject.asSelfObject();
addStatUpdateAction(context.mLuaManager, *obj);
obj->mStatsCache[SelfObject::CachedStat{ &ItemData::setValue, std::monostate{}, prop }] = value;
}
sol::object getValue(const Context& context, std::string_view prop) const
{
if (prop == "condition")
{
MWWorld::Ptr o = mObject.ptr();
if (o.getClass().isLight(o))
return sol::make_object(context.mLua->sol(), o.getClass().getRemainingUsageTime(o));
else if (o.getClass().hasItemHealth(o))
return sol::make_object(context.mLua->sol(), o.getClass().getItemHealth(o));
}
return sol::lua_nil;
}
static void setValue(Index i, std::string_view prop, const MWWorld::Ptr& ptr, const sol::object& value)
{
if (prop == "condition")
{
double cond = value.as<double>();
if (ptr.getClass().isLight(ptr))
ptr.getClass().setRemainingUsageTime(ptr, cond);
else if (ptr.getClass().hasItemHealth(ptr))
ptr.getCellRef().setCharge(std::max(0, static_cast<int>(cond)));
else /*ignore or error?*/
invalidPropErr(prop, ptr);
}
}
};
}
namespace sol
{
template <>
struct is_automagical<MWLua::ItemData> : std::false_type
{
};
}
namespace MWLua
{
void addItemDataBindings(sol::table& item, const Context& context)
{
item["itemData"] = [](const sol::object& object) -> sol::optional<ItemData> {
ObjectVariant o(object);
if (o.ptr().getClass().isItem(o.ptr()) || o.ptr().mRef->getType() == ESM::REC_LIGH)
return ItemData(std::move(o));
return {};
};
sol::usertype<ItemData> itemData = context.mLua->sol().new_usertype<ItemData>("ItemData");
itemData[sol::meta_function::new_index] = [](const ItemData& stat, const sol::variadic_args args) {
throw std::runtime_error("Unknown ItemData property '" + args.get<std::string>() + "'");
};
for (std::string_view prop : properties)
{
itemData[prop] = sol::property([context, prop](const ItemData& stat) { return stat.get(context, prop); },
[context, prop](const ItemData& stat, const sol::object& value) { stat.set(context, prop, value); });
}
}
}

View file

@ -0,0 +1,13 @@
#ifndef MWLUA_ITEMDATA_H
#define MWLUA_ITEMDATA_H
#include <sol/forward.hpp>
namespace MWLua
{
struct Context;
void addItemDataBindings(sol::table& item, const Context& context);
}
#endif // MWLUA_ITEMDATA_H

View file

@ -22,7 +22,7 @@ namespace MWLua
class CachedStat class CachedStat
{ {
public: public:
using Index = std::variant<int, ESM::RefId>; using Index = std::variant<int, ESM::RefId, std::monostate>;
using Setter = void (*)(const Index&, std::string_view, const MWWorld::Ptr&, const sol::object&); using Setter = void (*)(const Index&, std::string_view, const MWWorld::Ptr&, const sol::object&);
CachedStat(Setter setter, Index index, std::string_view prop) CachedStat(Setter setter, Index index, std::string_view prop)

View file

@ -1,31 +1,22 @@
#include "itemstats.hpp" #include <sol/sol.hpp>
namespace sol #include "../../mwworld/class.hpp"
{
template <> #include "../itemdata.hpp"
struct is_automagical<MWLua::ItemStat> : std::false_type
{ #include "types.hpp"
};
}
namespace MWLua namespace MWLua
{ {
void addItemBindings(sol::table item, const Context& context) void addItemBindings(sol::table item, const Context& context)
{ {
sol::usertype<ItemStat> ItemStats = context.mLua->sol().new_usertype<ItemStat>("ItemStat");
ItemStats[sol::meta_function::new_index] = [](const ItemStat& i, const sol::variadic_args args) {
throw std::runtime_error("Unknown itemStat property '" + args.get<std::string>() + "'");
};
ItemStats["condition"] = sol::property([](const ItemStat& i) { return i.getCondition(); },
[](const ItemStat& i, float cond) { i.setCondition(cond); });
item["getEnchantmentCharge"] item["getEnchantmentCharge"]
= [](const Object& object) { return object.ptr().getCellRef().getEnchantmentCharge(); }; = [](const Object& object) { return object.ptr().getCellRef().getEnchantmentCharge(); };
item["setEnchantmentCharge"] item["setEnchantmentCharge"]
= [](const GObject& object, float charge) { object.ptr().getCellRef().setEnchantmentCharge(charge); }; = [](const GObject& object, float charge) { object.ptr().getCellRef().setEnchantmentCharge(charge); };
item["isRestocking"] item["isRestocking"]
= [](const Object& object) -> bool { return object.ptr().getRefData().getCount(false) < 0; }; = [](const Object& object) -> bool { return object.ptr().getRefData().getCount(false) < 0; };
item["itemStats"] = [](const sol::object& object) { return ItemStat(object); };
addItemDataBindings(item, context);
} }
} }

View file

@ -1,33 +0,0 @@
#include "itemstats.hpp"
namespace MWLua
{
ItemStat::ItemStat(const sol::object& object)
: mObject(ObjectVariant(object))
{
}
sol::optional<double> ItemStat::getCondition() const
{
MWWorld::Ptr o = mObject.ptr();
if (o.getClass().isLight(o))
return o.getClass().getRemainingUsageTime(o);
else if (o.getClass().hasItemHealth(o))
return o.getClass().getItemHealth(o);
else
return sol::nullopt;
}
void ItemStat::setCondition(float cond) const
{
if (!mObject.isGObject())
throw std::runtime_error("This property can only be set in global scripts");
MWWorld::Ptr o = mObject.ptr();
if (o.getClass().isLight(o))
return o.getClass().setRemainingUsageTime(o, cond);
else if (o.getClass().hasItemHealth(o))
o.getCellRef().setCharge(std::max(0, static_cast<int>(cond)));
else
throw std::runtime_error("'condition' property does not exist for " + std::string(o.getClass().getName(o))
+ "(" + std::string(o.getTypeDescription()) + ")");
};
}

View file

@ -1,29 +0,0 @@
#ifndef MWLUA_ITEMSTATS_H
#define MWLUA_ITEMSTATS_H
#include <sol/sol.hpp>
#include "../../mwworld/class.hpp"
#include "../objectvariant.hpp"
#include "types.hpp"
namespace MWLua
{
class ItemStat
{
public:
ItemStat(const sol::object& object);
sol::optional<double> getCondition() const;
void setCondition(float cond) const;
/*
* set,get, enchantmentCharge, soul? etc..
*/
ObjectVariant mObject;
};
}
#endif // MWLUA_ITEMSTATS_H