Merge branch 'lua_sgetcurrent_conditionofitem_itemdata_idea' into 'master'

Lua API to get/set item condition

See merge request OpenMW/openmw!3421
macos_ci_fix
Zackhasacat 6 months ago
commit 5623a5cf01

@ -62,7 +62,7 @@ add_openmw_dir (mwscript
add_openmw_dir (mwlua
luamanagerimp object objectlists userdataserializer luaevents engineevents objectvariant
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
worker magicbindings factionbindings classbindings
)

@ -0,0 +1,134 @@
#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) + "'" + " property 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.mRef->getType() == ESM::REC_LIGH)
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) + o.getCellRef().getChargeIntRemainder());
}
return sol::lua_nil;
}
static void setValue(Index i, std::string_view prop, const MWWorld::Ptr& ptr, const sol::object& value)
{
if (prop == "condition")
{
float cond = LuaUtil::cast<float>(value);
if (ptr.mRef->getType() == ESM::REC_LIGH)
ptr.getClass().setRemainingUsageTime(ptr, cond);
else if (ptr.getClass().hasItemHealth(ptr))
{
// if the value set is less than 0, chargeInt and chargeIntRemainder is set to 0
ptr.getCellRef().setChargeIntRemainder(std::max(0.f, std::modf(cond, &cond)));
ptr.getCellRef().setCharge(std::max(0.f, cond));
}
else
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); });
}
}
}

@ -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

@ -22,7 +22,7 @@ namespace MWLua
class CachedStat
{
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&);
CachedStat(Setter setter, Index index, std::string_view prop)

@ -85,7 +85,7 @@ namespace MWLua
public:
sol::object getCurrent(const Context& context) const
{
return getValue(context, mObject, &LevelStat::setValue, 0, "current",
return getValue(context, mObject, &LevelStat::setValue, std::monostate{}, "current",
[](const MWWorld::Ptr& ptr) { return ptr.getClass().getCreatureStats(ptr).getLevel(); });
}
@ -93,7 +93,7 @@ namespace MWLua
{
SelfObject* obj = mObject.asSelfObject();
addStatUpdateAction(context.mLuaManager, *obj);
obj->mStatsCache[SelfObject::CachedStat{ &LevelStat::setValue, 0, "current" }] = value;
obj->mStatsCache[SelfObject::CachedStat{ &LevelStat::setValue, std::monostate{}, "current" }] = value;
}
sol::object getProgress(const Context& context) const

@ -2,11 +2,13 @@
#include "../../mwworld/class.hpp"
#include "../itemdata.hpp"
#include "types.hpp"
namespace MWLua
{
void addItemBindings(sol::table item)
void addItemBindings(sol::table item, const Context& context)
{
item["getEnchantmentCharge"]
= [](const Object& object) { return object.ptr().getCellRef().getEnchantmentCharge(); };
@ -14,5 +16,7 @@ namespace MWLua
= [](const GObject& object, float charge) { object.ptr().getCellRef().setEnchantmentCharge(charge); };
item["isRestocking"]
= [](const Object& object) -> bool { return object.ptr().getRefData().getCount(false) < 0; };
addItemDataBindings(item, context);
}
}

@ -191,9 +191,11 @@ namespace MWLua
addActorBindings(
addType(ObjectTypeName::Actor, { ESM::REC_INTERNAL_PLAYER, ESM::REC_CREA, ESM::REC_NPC_ }), context);
addItemBindings(addType(ObjectTypeName::Item,
{ ESM::REC_ARMO, ESM::REC_BOOK, ESM::REC_CLOT, ESM::REC_INGR, ESM::REC_LIGH, ESM::REC_MISC, ESM::REC_ALCH,
ESM::REC_WEAP, ESM::REC_APPA, ESM::REC_LOCK, ESM::REC_PROB, ESM::REC_REPA }));
addItemBindings(
addType(ObjectTypeName::Item,
{ ESM::REC_ARMO, ESM::REC_BOOK, ESM::REC_CLOT, ESM::REC_INGR, ESM::REC_LIGH, ESM::REC_MISC,
ESM::REC_ALCH, ESM::REC_WEAP, ESM::REC_APPA, ESM::REC_LOCK, ESM::REC_PROB, ESM::REC_REPA }),
context);
addLockableBindings(
addType(ObjectTypeName::Lockable, { ESM::REC_CONT, ESM::REC_DOOR, ESM::REC_CONT4, ESM::REC_DOOR4 }));

@ -47,7 +47,7 @@ namespace MWLua
void addBookBindings(sol::table book, const Context& context);
void addContainerBindings(sol::table container, const Context& context);
void addDoorBindings(sol::table door, const Context& context);
void addItemBindings(sol::table item);
void addItemBindings(sol::table item, const Context& context);
void addActorBindings(sol::table actor, const Context& context);
void addWeaponBindings(sol::table weapon, const Context& context);
void addNpcBindings(sol::table npc, const Context& context);

@ -188,19 +188,14 @@ namespace MWWorld
void CellRef::applyChargeRemainderToBeSubtracted(float chargeRemainder)
{
auto esm3Visit = [&](ESM::CellRef& cellRef3) {
cellRef3.mChargeIntRemainder += std::abs(chargeRemainder);
if (cellRef3.mChargeIntRemainder > 1.0f)
cellRef3.mChargeIntRemainder -= std::abs(chargeRemainder);
if (cellRef3.mChargeIntRemainder <= -1.0f)
{
float newChargeRemainder = (cellRef3.mChargeIntRemainder - std::floor(cellRef3.mChargeIntRemainder));
if (cellRef3.mChargeInt <= static_cast<int>(cellRef3.mChargeIntRemainder))
{
cellRef3.mChargeInt = 0;
}
else
{
cellRef3.mChargeInt -= static_cast<int>(cellRef3.mChargeIntRemainder);
}
float newChargeRemainder = std::modf(cellRef3.mChargeIntRemainder, &cellRef3.mChargeIntRemainder);
cellRef3.mChargeInt += static_cast<int>(cellRef3.mChargeIntRemainder);
cellRef3.mChargeIntRemainder = newChargeRemainder;
if (cellRef3.mChargeInt < 0)
cellRef3.mChargeInt = 0;
}
};
std::visit(ESM::VisitOverload{
@ -211,6 +206,16 @@ namespace MWWorld
mCellRef.mVariant);
}
void CellRef::setChargeIntRemainder(float chargeRemainder)
{
std::visit(ESM::VisitOverload{
[&](ESM4::Reference& /*ref*/) {},
[&](ESM4::ActorCharacter&) {},
[&](ESM::CellRef& ref) { ref.mChargeIntRemainder = chargeRemainder; },
},
mCellRef.mVariant);
}
void CellRef::setChargeFloat(float charge)
{
std::visit(ESM::VisitOverload{

@ -118,9 +118,22 @@ namespace MWWorld
};
return std::visit(Visitor(), mCellRef.mVariant);
} // Implemented as union with int charge
float getChargeIntRemainder() const
{
struct Visitor
{
float operator()(const ESM::CellRef& ref) { return ref.mChargeIntRemainder; }
float operator()(const ESM4::Reference& /*ref*/) { return 0; }
float operator()(const ESM4::ActorCharacter&) { throw std::logic_error("Not applicable"); }
};
return std::visit(Visitor(), mCellRef.mVariant);
}
void setCharge(int charge);
void setChargeFloat(float charge);
void applyChargeRemainderToBeSubtracted(float chargeRemainder); // Stores remainders and applies if > 1
void applyChargeRemainderToBeSubtracted(float chargeRemainder); // Stores remainders and applies if <= -1
// Stores fractional part of mChargeInt
void setChargeIntRemainder(float chargeRemainder);
// The NPC that owns this object (and will get angry if you steal it)
ESM::RefId getOwner() const

@ -60,7 +60,7 @@ namespace ESM
int32_t mChargeInt; // Used by everything except lights
float mChargeFloat; // Used only by lights
};
float mChargeIntRemainder; // Stores amount of charge not subtracted from mChargeInt
float mChargeIntRemainder; // Fractional part of mChargeInt
// Remaining enchantment charge. This could be -1 if the charge was not touched yet (i.e. full).
float mEnchantmentCharge;

@ -675,6 +675,15 @@
-- @param openmw.core#GameObject object
-- @return #boolean
---
-- Set of properties that differentiates one item from another of the same record type.
-- @function [parent=#Item] itemData
-- @param openmw.core#GameObject item
-- @return #ItemData
---
-- @type ItemData
-- @field #number condition The item's current condition. Time remaining for lights. Uses left for lockpicks and probes. Current health for weapons and armor.
--------------------------------------------------------------------------------
-- @{#Creature} functions

Loading…
Cancel
Save