mirror of
https://github.com/OpenMW/openmw.git
synced 2025-01-30 08:15:37 +00:00
Merge branch 'lua_sgetcurrent_conditionofitem_itemdata_idea' into 'master'
Lua API to get/set item condition See merge request OpenMW/openmw!3421
This commit is contained in:
commit
5623a5cf01
12 changed files with 202 additions and 22 deletions
|
@ -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
|
||||
)
|
||||
|
|
134
apps/openmw/mwlua/itemdata.cpp
Normal file
134
apps/openmw/mwlua/itemdata.cpp
Normal file
|
@ -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); });
|
||||
}
|
||||
}
|
||||
}
|
13
apps/openmw/mwlua/itemdata.hpp
Normal file
13
apps/openmw/mwlua/itemdata.hpp
Normal 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
|
|
@ -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…
Reference in a new issue