mirror of
https://github.com/OpenMW/openmw.git
synced 2025-02-28 22:09:42 +00:00
Lua bindings for magic. Based on the work made by @bharbich in !2765.
This commit is contained in:
parent
0a9d937cfe
commit
90397662bc
13 changed files with 517 additions and 28 deletions
|
@ -63,7 +63,7 @@ add_openmw_dir (mwlua
|
||||||
context globalscripts localscripts playerscripts luabindings objectbindings cellbindings
|
context globalscripts localscripts playerscripts luabindings objectbindings cellbindings
|
||||||
camerabindings uibindings inputbindings nearbybindings postprocessingbindings stats debugbindings
|
camerabindings uibindings inputbindings nearbybindings postprocessingbindings stats debugbindings
|
||||||
types/types types/door types/actor types/container types/weapon types/npc types/creature 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/types types/door types/actor types/container types/weapon types/npc types/creature 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
|
||||||
worker
|
worker magicbindings
|
||||||
)
|
)
|
||||||
|
|
||||||
add_openmw_dir (mwsound
|
add_openmw_dir (mwsound
|
||||||
|
|
|
@ -2,7 +2,10 @@
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
|
||||||
|
#include <components/esm/attr.hpp>
|
||||||
|
#include <components/esm3/activespells.hpp>
|
||||||
#include <components/esm3/loadalch.hpp>
|
#include <components/esm3/loadalch.hpp>
|
||||||
|
#include <components/esm3/loadskil.hpp>
|
||||||
#include <components/lua/l10n.hpp>
|
#include <components/lua/l10n.hpp>
|
||||||
#include <components/lua/luastate.hpp>
|
#include <components/lua/luastate.hpp>
|
||||||
|
|
||||||
|
@ -19,6 +22,8 @@
|
||||||
#include "luamanagerimp.hpp"
|
#include "luamanagerimp.hpp"
|
||||||
#include "worldview.hpp"
|
#include "worldview.hpp"
|
||||||
|
|
||||||
|
#include "magicbindings.hpp"
|
||||||
|
|
||||||
namespace MWLua
|
namespace MWLua
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -53,7 +58,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"] = 35;
|
api["API_REVISION"] = 36;
|
||||||
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();
|
||||||
MWBase::Environment::get().getStateManager()->requestQuit();
|
MWBase::Environment::get().getStateManager()->requestQuit();
|
||||||
|
@ -63,6 +68,7 @@ namespace MWLua
|
||||||
{ std::move(eventName), LuaUtil::serialize(eventData, context.mSerializer) });
|
{ std::move(eventName), LuaUtil::serialize(eventData, context.mSerializer) });
|
||||||
};
|
};
|
||||||
addTimeBindings(api, context, false);
|
addTimeBindings(api, context, false);
|
||||||
|
api["magic"] = initCoreMagicBindings(context);
|
||||||
api["l10n"] = LuaUtil::initL10nLoader(lua->sol(), MWBase::Environment::get().getL10nManager());
|
api["l10n"] = LuaUtil::initL10nLoader(lua->sol(), MWBase::Environment::get().getL10nManager());
|
||||||
const MWWorld::Store<ESM::GameSetting>* gmst
|
const MWWorld::Store<ESM::GameSetting>* gmst
|
||||||
= &MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
= &MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
||||||
|
@ -75,6 +81,18 @@ namespace MWLua
|
||||||
else
|
else
|
||||||
return sol::make_object<float>(lua->sol(), value.getFloat());
|
return sol::make_object<float>(lua->sol(), value.getFloat());
|
||||||
};
|
};
|
||||||
|
|
||||||
|
sol::table skill(context.mLua->sol(), sol::create);
|
||||||
|
api["SKILL"] = LuaUtil::makeStrictReadOnly(skill);
|
||||||
|
for (int id = 0; id < ESM::Skill::Length; ++id)
|
||||||
|
skill[ESM::Skill::sSkillNames[id]] = Misc::StringUtils::lowerCase(ESM::Skill::sSkillNames[id]);
|
||||||
|
|
||||||
|
sol::table attribute(context.mLua->sol(), sol::create);
|
||||||
|
api["ATTRIBUTE"] = LuaUtil::makeStrictReadOnly(attribute);
|
||||||
|
for (int id = 0; id < ESM::Attribute::Length; ++id)
|
||||||
|
attribute[ESM::Attribute::sAttributeNames[id]]
|
||||||
|
= Misc::StringUtils::lowerCase(ESM::Attribute::sAttributeNames[id]);
|
||||||
|
|
||||||
return LuaUtil::makeReadOnly(api);
|
return LuaUtil::makeReadOnly(api);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,7 +115,7 @@ namespace MWLua
|
||||||
const MWWorld::Ptr& ptr = mref.getPtr();
|
const MWWorld::Ptr& ptr = mref.getPtr();
|
||||||
ptr.getRefData().disable();
|
ptr.getRefData().disable();
|
||||||
MWWorld::Ptr newPtr = ptr.getClass().copyToCell(ptr, *cell, count.value_or(1));
|
MWWorld::Ptr newPtr = ptr.getClass().copyToCell(ptr, *cell, count.value_or(1));
|
||||||
return GObject(getId(newPtr));
|
return GObject(newPtr);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Creates a new record in the world database.
|
// Creates a new record in the world database.
|
||||||
|
|
266
apps/openmw/mwlua/magicbindings.cpp
Normal file
266
apps/openmw/mwlua/magicbindings.cpp
Normal file
|
@ -0,0 +1,266 @@
|
||||||
|
#include "magicbindings.hpp"
|
||||||
|
|
||||||
|
#include <components/esm3/activespells.hpp>
|
||||||
|
#include <components/esm3/loadmgef.hpp>
|
||||||
|
#include <components/esm3/loadspel.hpp>
|
||||||
|
#include <components/lua/luastate.hpp>
|
||||||
|
#include <components/misc/color.hpp>
|
||||||
|
#include <components/misc/resourcehelpers.hpp>
|
||||||
|
#include <components/resource/resourcesystem.hpp>
|
||||||
|
|
||||||
|
#include "../mwbase/environment.hpp"
|
||||||
|
#include "../mwbase/world.hpp"
|
||||||
|
#include "../mwmechanics/activespells.hpp"
|
||||||
|
#include "../mwmechanics/creaturestats.hpp"
|
||||||
|
#include "../mwmechanics/npcstats.hpp"
|
||||||
|
#include "../mwworld/action.hpp"
|
||||||
|
#include "../mwworld/class.hpp"
|
||||||
|
#include "../mwworld/esmstore.hpp"
|
||||||
|
|
||||||
|
#include "localscripts.hpp"
|
||||||
|
#include "luamanagerimp.hpp"
|
||||||
|
#include "object.hpp"
|
||||||
|
#include "objectvariant.hpp"
|
||||||
|
#include "worldview.hpp"
|
||||||
|
|
||||||
|
namespace MWLua
|
||||||
|
{
|
||||||
|
sol::table initCoreMagicBindings(const Context& context)
|
||||||
|
{
|
||||||
|
sol::state_view& lua = context.mLua->sol();
|
||||||
|
sol::table magicApi(lua, sol::create);
|
||||||
|
|
||||||
|
// Constants
|
||||||
|
magicApi["RANGE"] = LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs<std::string_view, ESM::RangeType>({
|
||||||
|
{ "Self", ESM::RT_Self },
|
||||||
|
{ "Touch", ESM::RT_Touch },
|
||||||
|
{ "Target", ESM::RT_Target },
|
||||||
|
}));
|
||||||
|
magicApi["SCHOOL"] = LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs<std::string_view, int>({
|
||||||
|
{ "Alteration", 0 },
|
||||||
|
{ "Conjuration", 1 },
|
||||||
|
{ "Destruction", 2 },
|
||||||
|
{ "Illusion", 3 },
|
||||||
|
{ "Mysticism", 4 },
|
||||||
|
{ "Restoration", 5 },
|
||||||
|
}));
|
||||||
|
magicApi["SPELL_TYPE"]
|
||||||
|
= LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs<std::string_view, ESM::Spell::SpellType>({
|
||||||
|
{ "Spell", ESM::Spell::ST_Spell },
|
||||||
|
{ "Ability", ESM::Spell::ST_Ability },
|
||||||
|
{ "Blight", ESM::Spell::ST_Blight },
|
||||||
|
{ "Disease", ESM::Spell::ST_Disease },
|
||||||
|
{ "Curse", ESM::Spell::ST_Curse },
|
||||||
|
{ "Power", ESM::Spell::ST_Power },
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Spell store
|
||||||
|
using SpellStore = MWWorld::Store<ESM::Spell>;
|
||||||
|
const SpellStore* spellStore = &MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>();
|
||||||
|
sol::usertype<SpellStore> spellStoreT = lua.new_usertype<SpellStore>("ESM3_SpellStore");
|
||||||
|
spellStoreT[sol::meta_function::to_string]
|
||||||
|
= [](const SpellStore& store) { return "ESM3_SpellStore{" + std::to_string(store.getSize()) + " spells}"; };
|
||||||
|
spellStoreT[sol::meta_function::length] = [](const SpellStore& store) { return store.getSize(); };
|
||||||
|
spellStoreT[sol::meta_function::index] = sol::overload(
|
||||||
|
[](const SpellStore& store, size_t index) -> const ESM::Spell* { return store.at(index - 1); },
|
||||||
|
[](const SpellStore& store, std::string_view spellId) -> const ESM::Spell* {
|
||||||
|
return store.find(ESM::RefId::deserializeText(spellId));
|
||||||
|
});
|
||||||
|
spellStoreT[sol::meta_function::pairs] = lua["ipairsForArray"].template get<sol::function>();
|
||||||
|
spellStoreT[sol::meta_function::ipairs] = lua["ipairsForArray"].template get<sol::function>();
|
||||||
|
|
||||||
|
magicApi["spells"] = spellStore;
|
||||||
|
|
||||||
|
// MagicEffect store
|
||||||
|
using MagicEffectStore = MWWorld::Store<ESM::MagicEffect>;
|
||||||
|
const MagicEffectStore* magicEffectStore
|
||||||
|
= &MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>();
|
||||||
|
auto magicEffectStoreT = lua.new_usertype<MagicEffectStore>("ESM3_MagicEffectStore");
|
||||||
|
magicEffectStoreT[sol::meta_function::to_string] = [](const MagicEffectStore& store) {
|
||||||
|
return "ESM3_MagicEffectStore{" + std::to_string(store.getSize()) + " effects}";
|
||||||
|
};
|
||||||
|
magicEffectStoreT[sol::meta_function::index]
|
||||||
|
= [](const MagicEffectStore& store, int id) -> const ESM::MagicEffect* { return store.find(id); };
|
||||||
|
auto magicEffectsIter = [magicEffectStore](sol::this_state lua, const sol::object& /*store*/,
|
||||||
|
sol::optional<int> id) -> std::tuple<sol::object, sol::object> {
|
||||||
|
MagicEffectStore::iterator iter;
|
||||||
|
if (id.has_value())
|
||||||
|
{
|
||||||
|
iter = magicEffectStore->findIter(*id);
|
||||||
|
if (iter != magicEffectStore->end())
|
||||||
|
iter++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
iter = magicEffectStore->begin();
|
||||||
|
if (iter != magicEffectStore->end())
|
||||||
|
return std::make_tuple(sol::make_object(lua, iter->first), sol::make_object(lua, &iter->second));
|
||||||
|
else
|
||||||
|
return std::make_tuple(sol::nil, sol::nil);
|
||||||
|
};
|
||||||
|
magicEffectStoreT[sol::meta_function::pairs]
|
||||||
|
= [iter = sol::make_object(lua, magicEffectsIter)] { return iter; };
|
||||||
|
|
||||||
|
magicApi["effects"] = magicEffectStore;
|
||||||
|
|
||||||
|
// Spell record
|
||||||
|
auto spellT = lua.new_usertype<ESM::Spell>("ESM3_Spell");
|
||||||
|
spellT[sol::meta_function::to_string]
|
||||||
|
= [](const ESM::Spell& rec) -> std::string { return "ESM3_Spell[" + rec.mId.toDebugString() + "]"; };
|
||||||
|
spellT["id"] = sol::readonly_property([](const ESM::Spell& rec) { return rec.mId.serializeText(); });
|
||||||
|
spellT["name"] = sol::readonly_property([](const ESM::Spell& rec) -> std::string_view { return rec.mName; });
|
||||||
|
spellT["type"] = sol::readonly_property([](const ESM::Spell& rec) -> int { return rec.mData.mType; });
|
||||||
|
spellT["cost"] = sol::readonly_property([](const ESM::Spell& rec) -> int { return rec.mData.mCost; });
|
||||||
|
spellT["effects"] = sol::readonly_property([&lua](const ESM::Spell& rec) -> sol::table {
|
||||||
|
sol::table res(lua, sol::create);
|
||||||
|
for (size_t i = 0; i < rec.mEffects.mList.size(); ++i)
|
||||||
|
res[i + 1] = rec.mEffects.mList[i]; // ESM::ENAMstruct (effect params)
|
||||||
|
return res;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Effect params
|
||||||
|
auto effectParamsT = lua.new_usertype<ESM::ENAMstruct>("ESM3_EffectParams");
|
||||||
|
effectParamsT[sol::meta_function::to_string] = [magicEffectStore](const ESM::ENAMstruct& params) {
|
||||||
|
const ESM::MagicEffect* const rec = magicEffectStore->find(params.mEffectID);
|
||||||
|
return "ESM3_EffectParams[" + ESM::MagicEffect::effectIdToString(rec->mIndex) + "]";
|
||||||
|
};
|
||||||
|
effectParamsT["effect"]
|
||||||
|
= sol::readonly_property([magicEffectStore](const ESM::ENAMstruct& params) -> const ESM::MagicEffect* {
|
||||||
|
return magicEffectStore->find(params.mEffectID);
|
||||||
|
});
|
||||||
|
effectParamsT["affectedSkill"]
|
||||||
|
= sol::readonly_property([](const ESM::ENAMstruct& params) -> sol::optional<std::string> {
|
||||||
|
if (params.mSkill >= 0 && params.mSkill < ESM::Skill::Length)
|
||||||
|
return Misc::StringUtils::lowerCase(ESM::Skill::sSkillNames[params.mSkill]);
|
||||||
|
else
|
||||||
|
return sol::nullopt;
|
||||||
|
});
|
||||||
|
effectParamsT["affectedAttribute"]
|
||||||
|
= sol::readonly_property([](const ESM::ENAMstruct& params) -> sol::optional<std::string> {
|
||||||
|
if (params.mAttribute >= 0 && params.mAttribute < ESM::Attribute::Length)
|
||||||
|
return Misc::StringUtils::lowerCase(ESM::Attribute::sAttributeNames[params.mAttribute]);
|
||||||
|
else
|
||||||
|
return sol::nullopt;
|
||||||
|
});
|
||||||
|
effectParamsT["range"]
|
||||||
|
= sol::readonly_property([](const ESM::ENAMstruct& params) -> int { return params.mRange; });
|
||||||
|
effectParamsT["area"]
|
||||||
|
= sol::readonly_property([](const ESM::ENAMstruct& params) -> int { return params.mArea; });
|
||||||
|
effectParamsT["magnitudeMin"]
|
||||||
|
= sol::readonly_property([](const ESM::ENAMstruct& params) -> int { return params.mMagnMin; });
|
||||||
|
effectParamsT["magnitudeMax"]
|
||||||
|
= sol::readonly_property([](const ESM::ENAMstruct& params) -> int { return params.mMagnMax; });
|
||||||
|
|
||||||
|
// MagicEffect record
|
||||||
|
auto magicEffectT = context.mLua->sol().new_usertype<ESM::MagicEffect>("ESM3_MagicEffect");
|
||||||
|
|
||||||
|
magicEffectT[sol::meta_function::to_string] = [](const ESM::MagicEffect& rec) {
|
||||||
|
return "ESM3_MagicEffect[" + ESM::MagicEffect::effectIdToString(rec.mIndex) + "]";
|
||||||
|
};
|
||||||
|
magicEffectT["id"] = sol::readonly_property([](const ESM::MagicEffect& rec) -> int { return rec.mIndex; });
|
||||||
|
magicEffectT["name"] = sol::readonly_property([](const ESM::MagicEffect& rec) -> std::string_view {
|
||||||
|
return MWBase::Environment::get()
|
||||||
|
.getWorld()
|
||||||
|
->getStore()
|
||||||
|
.get<ESM::GameSetting>()
|
||||||
|
.find(ESM::MagicEffect::effectIdToString(rec.mIndex))
|
||||||
|
->mValue.getString();
|
||||||
|
});
|
||||||
|
magicEffectT["school"]
|
||||||
|
= sol::readonly_property([](const ESM::MagicEffect& rec) -> int { return rec.mData.mSchool; });
|
||||||
|
magicEffectT["baseCost"]
|
||||||
|
= sol::readonly_property([](const ESM::MagicEffect& rec) -> float { return rec.mData.mBaseCost; });
|
||||||
|
magicEffectT["color"] = sol::readonly_property([](const ESM::MagicEffect& rec) -> Misc::Color {
|
||||||
|
return Misc::Color(rec.mData.mRed / 255.f, rec.mData.mGreen / 255.f, rec.mData.mBlue / 255.f, 1.f);
|
||||||
|
});
|
||||||
|
magicEffectT["harmful"] = sol::readonly_property(
|
||||||
|
[](const ESM::MagicEffect& rec) -> bool { return rec.mData.mFlags & ESM::MagicEffect::Harmful; });
|
||||||
|
|
||||||
|
// TODO: Should we expose it? What happens if a spell has several effects with different projectileSpeed?
|
||||||
|
// magicEffectT["projectileSpeed"]
|
||||||
|
// = sol::readonly_property([](const ESM::MagicEffect& rec) -> float { return rec.mData.mSpeed; });
|
||||||
|
|
||||||
|
return LuaUtil::makeReadOnly(magicApi);
|
||||||
|
}
|
||||||
|
|
||||||
|
// class returned via 'types.Actor.spells(obj)' in Lua
|
||||||
|
struct ActorSpells
|
||||||
|
{
|
||||||
|
const ObjectVariant mActor;
|
||||||
|
};
|
||||||
|
|
||||||
|
void addActorMagicBindings(sol::table& actor, const Context& context)
|
||||||
|
{
|
||||||
|
const MWWorld::Store<ESM::Spell>* spellStore
|
||||||
|
= &MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>();
|
||||||
|
|
||||||
|
// types.Actor.spells(o)
|
||||||
|
actor["spells"] = [](const sol::object actor) { return ActorSpells{ ObjectVariant(actor) }; };
|
||||||
|
auto spellsT = context.mLua->sol().new_usertype<ActorSpells>("ActorSpells");
|
||||||
|
spellsT[sol::meta_function::to_string]
|
||||||
|
= [](const ActorSpells& spells) { return "ActorSpells[" + spells.mActor.object().toString(); };
|
||||||
|
|
||||||
|
// #(types.Actor.spells(o))
|
||||||
|
spellsT[sol::meta_function::length] = [](const ActorSpells& spells) -> size_t {
|
||||||
|
const MWWorld::Ptr& ptr = spells.mActor.ptr();
|
||||||
|
return ptr.getClass().getCreatureStats(ptr).getSpells().count();
|
||||||
|
};
|
||||||
|
|
||||||
|
// types.Actor.spells(o)[i]
|
||||||
|
spellsT[sol::meta_function::index] = sol::overload(
|
||||||
|
[](const ActorSpells& spells, size_t index) -> const ESM::Spell* {
|
||||||
|
const MWWorld::Ptr& ptr = spells.mActor.ptr();
|
||||||
|
return ptr.getClass().getCreatureStats(ptr).getSpells().at(index - 1);
|
||||||
|
},
|
||||||
|
[spellStore](const ActorSpells& spells, std::string_view spellId) -> sol::optional<const ESM::Spell*> {
|
||||||
|
const MWWorld::Ptr& ptr = spells.mActor.ptr();
|
||||||
|
const ESM::Spell* spell = spellStore->find(ESM::RefId::deserializeText(spellId));
|
||||||
|
if (ptr.getClass().getCreatureStats(ptr).getSpells().hasSpell(spell))
|
||||||
|
return spell;
|
||||||
|
else
|
||||||
|
return sol::nullopt;
|
||||||
|
});
|
||||||
|
|
||||||
|
// pairs(types.Actor.spells(o))
|
||||||
|
spellsT[sol::meta_function::pairs] = context.mLua->sol()["ipairsForArray"].template get<sol::function>();
|
||||||
|
|
||||||
|
// ipairs(types.Actor.spells(o))
|
||||||
|
spellsT[sol::meta_function::ipairs] = context.mLua->sol()["ipairsForArray"].template get<sol::function>();
|
||||||
|
|
||||||
|
auto toSpellId = [](const sol::object& spellOrId) -> ESM::RefId {
|
||||||
|
if (spellOrId.is<ESM::Spell>())
|
||||||
|
return spellOrId.as<const ESM::Spell*>()->mId;
|
||||||
|
else
|
||||||
|
return ESM::RefId::deserializeText(spellOrId.as<std::string_view>());
|
||||||
|
};
|
||||||
|
|
||||||
|
// types.Actor.spells(o):add(id)
|
||||||
|
spellsT["add"] = [context, toSpellId](const ActorSpells& spells, const sol::object& spellOrId) {
|
||||||
|
if (spells.mActor.isLObject())
|
||||||
|
throw std::runtime_error("Local scripts can modify only spells of the actor they are attached to.");
|
||||||
|
context.mLuaManager->addAction([obj = spells.mActor.object(), id = toSpellId(spellOrId)]() {
|
||||||
|
const MWWorld::Ptr& ptr = obj.ptr();
|
||||||
|
ptr.getClass().getCreatureStats(ptr).getSpells().add(id);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// types.Actor.spells(o):remove(id)
|
||||||
|
spellsT["remove"] = [context, toSpellId](const ActorSpells& spells, const sol::object& spellOrId) {
|
||||||
|
if (spells.mActor.isLObject())
|
||||||
|
throw std::runtime_error("Local scripts can modify only spells of the actor they are attached to.");
|
||||||
|
context.mLuaManager->addAction([obj = spells.mActor.object(), id = toSpellId(spellOrId)]() {
|
||||||
|
const MWWorld::Ptr& ptr = obj.ptr();
|
||||||
|
ptr.getClass().getCreatureStats(ptr).getSpells().remove(id);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// types.Actor.spells(o):clear()
|
||||||
|
spellsT["clear"] = [context](const ActorSpells& spells) {
|
||||||
|
if (spells.mActor.isLObject())
|
||||||
|
throw std::runtime_error("Local scripts can modify only spells of the actor they are attached to.");
|
||||||
|
context.mLuaManager->addAction([obj = spells.mActor.object()]() {
|
||||||
|
const MWWorld::Ptr& ptr = obj.ptr();
|
||||||
|
ptr.getClass().getCreatureStats(ptr).getSpells().clear();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
14
apps/openmw/mwlua/magicbindings.hpp
Normal file
14
apps/openmw/mwlua/magicbindings.hpp
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
#ifndef MWLUA_MAGICBINDINGS_H
|
||||||
|
#define MWLUA_MAGICBINDINGS_H
|
||||||
|
|
||||||
|
#include <sol/forward.hpp>
|
||||||
|
|
||||||
|
#include "context.hpp"
|
||||||
|
|
||||||
|
namespace MWLua
|
||||||
|
{
|
||||||
|
sol::table initCoreMagicBindings(const Context& context);
|
||||||
|
void addActorMagicBindings(sol::table& actor, const Context& context);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // MWLUA_MAGICBINDINGS_H
|
|
@ -29,9 +29,6 @@ namespace MWLua
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using SafePtr::SafePtr;
|
using SafePtr::SafePtr;
|
||||||
virtual sol::object getObject(lua_State* lua, ObjectId id) const = 0; // returns LObject or GObject
|
|
||||||
virtual sol::object getCell(lua_State* lua, MWWorld::CellStore* store) const = 0; // returns LCell or GCell
|
|
||||||
|
|
||||||
const MWWorld::Ptr& ptr() const
|
const MWWorld::Ptr& ptr() const
|
||||||
{
|
{
|
||||||
const MWWorld::Ptr& res = ptrOrNull();
|
const MWWorld::Ptr& res = ptrOrNull();
|
||||||
|
@ -49,11 +46,6 @@ namespace MWLua
|
||||||
class LObject : public Object
|
class LObject : public Object
|
||||||
{
|
{
|
||||||
using Object::Object;
|
using Object::Object;
|
||||||
sol::object getObject(lua_State* lua, ObjectId id) const final { return sol::make_object<LObject>(lua, id); }
|
|
||||||
sol::object getCell(lua_State* lua, MWWorld::CellStore* store) const final
|
|
||||||
{
|
|
||||||
return sol::make_object(lua, LCell{ store });
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Used only in global scripts
|
// Used only in global scripts
|
||||||
|
@ -64,11 +56,6 @@ namespace MWLua
|
||||||
class GObject : public Object
|
class GObject : public Object
|
||||||
{
|
{
|
||||||
using Object::Object;
|
using Object::Object;
|
||||||
sol::object getObject(lua_State* lua, ObjectId id) const final { return sol::make_object<GObject>(lua, id); }
|
|
||||||
sol::object getCell(lua_State* lua, MWWorld::CellStore* store) const final
|
|
||||||
{
|
|
||||||
return sol::make_object(lua, GCell{ store });
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
using ObjectIdList = std::shared_ptr<std::vector<ObjectId>>;
|
using ObjectIdList = std::shared_ptr<std::vector<ObjectId>>;
|
||||||
|
|
|
@ -46,6 +46,8 @@ namespace MWLua
|
||||||
mVariant);
|
mVariant);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Object object() const { return Object(ptr()); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::variant<SelfObject*, LObject, GObject> mVariant;
|
std::variant<SelfObject*, LObject, GObject> mVariant;
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
#include <apps/openmw/mwbase/mechanicsmanager.hpp>
|
#include <apps/openmw/mwbase/mechanicsmanager.hpp>
|
||||||
#include <apps/openmw/mwbase/windowmanager.hpp>
|
#include <apps/openmw/mwbase/windowmanager.hpp>
|
||||||
|
#include <apps/openmw/mwlua/luabindings.hpp>
|
||||||
#include <apps/openmw/mwmechanics/creaturestats.hpp>
|
#include <apps/openmw/mwmechanics/creaturestats.hpp>
|
||||||
#include <apps/openmw/mwmechanics/drawstate.hpp>
|
#include <apps/openmw/mwmechanics/drawstate.hpp>
|
||||||
#include <apps/openmw/mwworld/class.hpp>
|
#include <apps/openmw/mwworld/class.hpp>
|
||||||
|
@ -12,6 +13,7 @@
|
||||||
|
|
||||||
#include "../localscripts.hpp"
|
#include "../localscripts.hpp"
|
||||||
#include "../luamanagerimp.hpp"
|
#include "../luamanagerimp.hpp"
|
||||||
|
#include "../magicbindings.hpp"
|
||||||
#include "../stats.hpp"
|
#include "../stats.hpp"
|
||||||
|
|
||||||
namespace MWLua
|
namespace MWLua
|
||||||
|
@ -218,9 +220,9 @@ namespace MWLua
|
||||||
|
|
||||||
actor["inventory"] = sol::overload([](const LObject& o) { return Inventory<LObject>{ o }; },
|
actor["inventory"] = sol::overload([](const LObject& o) { return Inventory<LObject>{ o }; },
|
||||||
[](const GObject& o) { return Inventory<GObject>{ o }; });
|
[](const GObject& o) { return Inventory<GObject>{ o }; });
|
||||||
auto getAllEquipment = [context](const Object& o) {
|
auto getAllEquipment = [](sol::this_state lua, const Object& o) {
|
||||||
const MWWorld::Ptr& ptr = o.ptr();
|
const MWWorld::Ptr& ptr = o.ptr();
|
||||||
sol::table equipment(context.mLua->sol(), sol::create);
|
sol::table equipment(lua, sol::create);
|
||||||
if (!ptr.getClass().hasInventoryStore(ptr))
|
if (!ptr.getClass().hasInventoryStore(ptr))
|
||||||
return equipment;
|
return equipment;
|
||||||
|
|
||||||
|
@ -231,13 +233,15 @@ namespace MWLua
|
||||||
if (it == store.end())
|
if (it == store.end())
|
||||||
continue;
|
continue;
|
||||||
MWBase::Environment::get().getWorldModel()->registerPtr(*it);
|
MWBase::Environment::get().getWorldModel()->registerPtr(*it);
|
||||||
equipment[slot] = o.getObject(context.mLua->sol(), getId(*it));
|
if (dynamic_cast<const GObject*>(&o))
|
||||||
|
equipment[slot] = sol::make_object(lua, GObject(*it));
|
||||||
|
else
|
||||||
|
equipment[slot] = sol::make_object(lua, LObject(*it));
|
||||||
}
|
}
|
||||||
return equipment;
|
return equipment;
|
||||||
};
|
};
|
||||||
auto getEquipmentFromSlot = [context](const Object& o, int slot) -> sol::object {
|
auto getEquipmentFromSlot = [](sol::this_state lua, const Object& o, int slot) -> sol::object {
|
||||||
const MWWorld::Ptr& ptr = o.ptr();
|
const MWWorld::Ptr& ptr = o.ptr();
|
||||||
sol::table equipment(context.mLua->sol(), sol::create);
|
|
||||||
if (!ptr.getClass().hasInventoryStore(ptr))
|
if (!ptr.getClass().hasInventoryStore(ptr))
|
||||||
return sol::nil;
|
return sol::nil;
|
||||||
MWWorld::InventoryStore& store = ptr.getClass().getInventoryStore(ptr);
|
MWWorld::InventoryStore& store = ptr.getClass().getInventoryStore(ptr);
|
||||||
|
@ -245,7 +249,10 @@ namespace MWLua
|
||||||
if (it == store.end())
|
if (it == store.end())
|
||||||
return sol::nil;
|
return sol::nil;
|
||||||
MWBase::Environment::get().getWorldModel()->registerPtr(*it);
|
MWBase::Environment::get().getWorldModel()->registerPtr(*it);
|
||||||
return o.getObject(context.mLua->sol(), getId(*it));
|
if (dynamic_cast<const GObject*>(&o))
|
||||||
|
return sol::make_object(lua, GObject(*it));
|
||||||
|
else
|
||||||
|
return sol::make_object(lua, LObject(*it));
|
||||||
};
|
};
|
||||||
actor["equipment"] = sol::overload(getAllEquipment, getEquipmentFromSlot);
|
actor["equipment"] = sol::overload(getAllEquipment, getEquipmentFromSlot);
|
||||||
actor["hasEquipped"] = [](const Object& o, const Object& item) {
|
actor["hasEquipped"] = [](const Object& o, const Object& item) {
|
||||||
|
@ -274,16 +281,17 @@ namespace MWLua
|
||||||
context.mLuaManager->addAction(
|
context.mLuaManager->addAction(
|
||||||
std::make_unique<SetEquipmentAction>(context.mLua, obj.id(), std::move(eqp)));
|
std::make_unique<SetEquipmentAction>(context.mLua, obj.id(), std::move(eqp)));
|
||||||
};
|
};
|
||||||
actor["getPathfindingAgentBounds"] = [context](const LObject& o) {
|
actor["getPathfindingAgentBounds"] = [](sol::this_state lua, const LObject& o) {
|
||||||
const DetourNavigator::AgentBounds agentBounds
|
const DetourNavigator::AgentBounds agentBounds
|
||||||
= MWBase::Environment::get().getWorld()->getPathfindingAgentBounds(o.ptr());
|
= MWBase::Environment::get().getWorld()->getPathfindingAgentBounds(o.ptr());
|
||||||
sol::table result = context.mLua->newTable();
|
sol::table result(lua, sol::create);
|
||||||
result["shapeType"] = agentBounds.mShapeType;
|
result["shapeType"] = agentBounds.mShapeType;
|
||||||
result["halfExtents"] = agentBounds.mHalfExtents;
|
result["halfExtents"] = agentBounds.mHalfExtents;
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
addActorStatsBindings(actor, context);
|
addActorStatsBindings(actor, context);
|
||||||
|
addActorMagicBindings(actor, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,8 @@ namespace MWLua
|
||||||
{
|
{
|
||||||
void addBookBindings(sol::table book, const Context& context)
|
void addBookBindings(sol::table book, const Context& context)
|
||||||
{
|
{
|
||||||
|
// types.book.SKILL is deprecated (core.SKILL should be used instead)
|
||||||
|
// TODO: Remove book.SKILL after branching 0.49
|
||||||
sol::table skill(context.mLua->sol(), sol::create);
|
sol::table skill(context.mLua->sol(), sol::create);
|
||||||
book["SKILL"] = LuaUtil::makeStrictReadOnly(skill);
|
book["SKILL"] = LuaUtil::makeStrictReadOnly(skill);
|
||||||
for (int id = ESM::Skill::Block; id < ESM::Skill::Length; ++id)
|
for (int id = ESM::Skill::Block; id < ESM::Skill::Length; ++id)
|
||||||
|
|
|
@ -48,7 +48,10 @@ namespace MWLua
|
||||||
if (!cellRef.getTeleport())
|
if (!cellRef.getTeleport())
|
||||||
return sol::nil;
|
return sol::nil;
|
||||||
MWWorld::CellStore& cell = MWBase::Environment::get().getWorldModel()->getCell(cellRef.getDestCell());
|
MWWorld::CellStore& cell = MWBase::Environment::get().getWorldModel()->getCell(cellRef.getDestCell());
|
||||||
return o.getCell(lua, &cell);
|
if (dynamic_cast<const GObject*>(&o))
|
||||||
|
return sol::make_object(lua, GCell{ &cell });
|
||||||
|
else
|
||||||
|
return sol::make_object(lua, LCell{ &cell });
|
||||||
};
|
};
|
||||||
|
|
||||||
auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS();
|
auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS();
|
||||||
|
@ -84,7 +87,10 @@ namespace MWLua
|
||||||
if (!cellRef.getTeleport())
|
if (!cellRef.getTeleport())
|
||||||
return sol::nil;
|
return sol::nil;
|
||||||
MWWorld::CellStore& cell = MWBase::Environment::get().getWorldModel()->getCell(cellRef.getDestCell());
|
MWWorld::CellStore& cell = MWBase::Environment::get().getWorldModel()->getCell(cellRef.getDestCell());
|
||||||
return o.getCell(lua, &cell);
|
if (dynamic_cast<const GObject*>(&o))
|
||||||
|
return sol::make_object(lua, GCell{ &cell });
|
||||||
|
else
|
||||||
|
return sol::make_object(lua, LCell{ &cell });
|
||||||
};
|
};
|
||||||
|
|
||||||
auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS();
|
auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS();
|
||||||
|
|
|
@ -95,6 +95,10 @@ namespace MWMechanics
|
||||||
|
|
||||||
bool hasBlightDisease() const;
|
bool hasBlightDisease() const;
|
||||||
|
|
||||||
|
/// Iteration methods for lua
|
||||||
|
size_t count() const { return mSpells.size(); }
|
||||||
|
const ESM::Spell* at(size_t index) const { return mSpells.at(index); }
|
||||||
|
|
||||||
void readState(const ESM::SpellState& state, CreatureStats* creatureStats);
|
void readState(const ESM::SpellState& state, CreatureStats* creatureStats);
|
||||||
void writeState(ESM::SpellState& state) const;
|
void writeState(ESM::SpellState& state) const;
|
||||||
|
|
||||||
|
|
|
@ -94,6 +94,7 @@ namespace MWWorld
|
||||||
|
|
||||||
iterator begin() const;
|
iterator begin() const;
|
||||||
iterator end() const;
|
iterator end() const;
|
||||||
|
iterator findIter(int index) const { return mStatic.find(index); }
|
||||||
|
|
||||||
void load(ESM::ESMReader& esm);
|
void load(ESM::ESMReader& esm);
|
||||||
|
|
||||||
|
|
|
@ -292,4 +292,141 @@
|
||||||
-- @usage for _, item in ipairs(inventory:findAll('common_shirt_01')) do ... end
|
-- @usage for _, item in ipairs(inventory:findAll('common_shirt_01')) do ... end
|
||||||
|
|
||||||
|
|
||||||
|
--- Possible @{#ATTRIBUTE} values
|
||||||
|
-- @field [parent=#core] #ATTRIBUTE ATTRIBUTE
|
||||||
|
|
||||||
|
--- `core.ATTRIBUTE`
|
||||||
|
-- @type ATTRIBUTE
|
||||||
|
-- @field #string Strength "strength"
|
||||||
|
-- @field #string Intelligence "intelligence"
|
||||||
|
-- @field #string Willpower "willpower"
|
||||||
|
-- @field #string Agility "agility"
|
||||||
|
-- @field #string Speed "speed"
|
||||||
|
-- @field #string Endurance "endurance"
|
||||||
|
-- @field #string Personality "personality"
|
||||||
|
-- @field #string Luck "luck"
|
||||||
|
|
||||||
|
|
||||||
|
--- Possible @{#SKILL} values
|
||||||
|
-- @field [parent=#core] #SKILL SKILL
|
||||||
|
|
||||||
|
--- `core.SKILL`
|
||||||
|
-- @type SKILL
|
||||||
|
-- @field #string Acrobatics "acrobatics"
|
||||||
|
-- @field #string Alchemy "alchemy"
|
||||||
|
-- @field #string Alteration "alteration"
|
||||||
|
-- @field #string Armorer "armorer"
|
||||||
|
-- @field #string Athletics "athletics"
|
||||||
|
-- @field #string Axe "axe"
|
||||||
|
-- @field #string Block "block"
|
||||||
|
-- @field #string BluntWeapon "bluntweapon"
|
||||||
|
-- @field #string Conjuration "conjuration"
|
||||||
|
-- @field #string Destruction "destruction"
|
||||||
|
-- @field #string Enchant "enchant"
|
||||||
|
-- @field #string HandToHand "handtohand"
|
||||||
|
-- @field #string HeavyArmor "heavyarmor"
|
||||||
|
-- @field #string Illusion "illusion"
|
||||||
|
-- @field #string LightArmor "lightarmor"
|
||||||
|
-- @field #string LongBlade "longblade"
|
||||||
|
-- @field #string Marksman "marksman"
|
||||||
|
-- @field #string MediumArmor "mediumarmor"
|
||||||
|
-- @field #string Mercantile "mercantile"
|
||||||
|
-- @field #string Mysticism "mysticism"
|
||||||
|
-- @field #string Restoration "restoration"
|
||||||
|
-- @field #string Security "security"
|
||||||
|
-- @field #string ShortBlade "shortblade"
|
||||||
|
-- @field #string Sneak "sneak"
|
||||||
|
-- @field #string Spear "spear"
|
||||||
|
-- @field #string Speechcraft "speechcraft"
|
||||||
|
-- @field #string Unarmored "unarmored"
|
||||||
|
|
||||||
|
|
||||||
|
--- @{#Magic}: spells and spell effects
|
||||||
|
-- @field [parent=#core] #Magic magic
|
||||||
|
|
||||||
|
|
||||||
|
--- Possible @{#SpellRange} values
|
||||||
|
-- @field [parent=#Magic] #SpellRange RANGE
|
||||||
|
|
||||||
|
--- `core.magic.RANGE`
|
||||||
|
-- @type SpellRange
|
||||||
|
-- @field #number Self Applied on self
|
||||||
|
-- @field #number Touch On touch
|
||||||
|
-- @field #number Target Ranged spell
|
||||||
|
|
||||||
|
|
||||||
|
--- Possible @{#MagicSchool} values
|
||||||
|
-- @field [parent=#Magic] #MagicSchool SCHOOL
|
||||||
|
|
||||||
|
--- `core.magic.SCHOOL`
|
||||||
|
-- @type MagicSchool
|
||||||
|
-- @field #number Alteration Alteration
|
||||||
|
-- @field #number Conjuration Conjuration
|
||||||
|
-- @field #number Destruction Destruction
|
||||||
|
-- @field #number Illusion Illusion
|
||||||
|
-- @field #number Mysticism Mysticism
|
||||||
|
-- @field #number Restoration Restoration
|
||||||
|
|
||||||
|
|
||||||
|
--- Possible @{#SpellType} values
|
||||||
|
-- @field [parent=#Magic] #SpellType SPELL_TYPE
|
||||||
|
|
||||||
|
--- `core.magic.SPELL_TYPE`
|
||||||
|
-- @type SpellType
|
||||||
|
-- @field #number Spell Normal spell, must be cast and costs mana
|
||||||
|
-- @field #number Ability Inert ability, always in effect
|
||||||
|
-- @field #number Blight Blight disease
|
||||||
|
-- @field #number Disease Common disease
|
||||||
|
-- @field #number Curse Curse
|
||||||
|
-- @field #number Power Power, can be used once a day
|
||||||
|
|
||||||
|
|
||||||
|
--- List of all @{#Spell}s.
|
||||||
|
-- @field [parent=#Magic] #list<#Spell> spells
|
||||||
|
-- @usage local spell = core.magic.spells['thunder fist'] -- get by id
|
||||||
|
-- @usage local spell = core.magic.spells[1] -- get by index
|
||||||
|
-- @usage -- Print all powers
|
||||||
|
-- for _, spell in pairs(core.magic.spells) do
|
||||||
|
-- if spell.types == core.magic.SPELL_TYPE.Power then
|
||||||
|
-- print(spell.name)
|
||||||
|
-- end
|
||||||
|
-- end
|
||||||
|
|
||||||
|
--- Map from effectId to @{#SpellEffect}
|
||||||
|
-- @field [parent=#Magic] #map<#number, #MagicEffect> effects
|
||||||
|
-- @usage -- Print all harmful effects
|
||||||
|
-- for _, effect in pairs(core.magic.effects) do
|
||||||
|
-- if effect.harmful then
|
||||||
|
-- print(effect.name)
|
||||||
|
-- end
|
||||||
|
-- end
|
||||||
|
|
||||||
|
---
|
||||||
|
-- @type Spell
|
||||||
|
-- @field #string id Spell id
|
||||||
|
-- @field #string name Spell name
|
||||||
|
-- @field #number type @{#SpellType}
|
||||||
|
-- @field #number cost
|
||||||
|
-- @field #list<#MagicEffectWithParams> effects The effects (@{#MagicEffectWithParams}) of the spell
|
||||||
|
|
||||||
|
---
|
||||||
|
-- @type MagicEffect
|
||||||
|
-- @field #number id
|
||||||
|
-- @field #string name
|
||||||
|
-- @field #number school @{#MagicSchool}
|
||||||
|
-- @field #number baseCost
|
||||||
|
-- @field openmw.util#Color color
|
||||||
|
-- @field #boolean harmful
|
||||||
|
|
||||||
|
---
|
||||||
|
-- @type MagicEffectWithParams
|
||||||
|
-- @field #MagicEffect effect @{#MagicEffect}
|
||||||
|
-- @field #any affectedSkill @{#SKILL} or nil
|
||||||
|
-- @field #any affectedAttribute @{#ATTRIBUTE} or nil
|
||||||
|
-- @field #number range
|
||||||
|
-- @field #number area
|
||||||
|
-- @field #number magnitudeMin
|
||||||
|
-- @field #number magnitudeMax
|
||||||
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -149,6 +149,50 @@
|
||||||
-- local Actor = require('openmw.types').Actor
|
-- local Actor = require('openmw.types').Actor
|
||||||
-- Actor.setEquipment(self, {}) -- unequip all
|
-- Actor.setEquipment(self, {}) -- unequip all
|
||||||
|
|
||||||
|
---
|
||||||
|
-- Return the spells (@{ActorSpells}) of the given actor.
|
||||||
|
-- @function [parent=#Actor] spells
|
||||||
|
-- @param openmw.core#GameObject actor
|
||||||
|
-- @return #ActorSpells
|
||||||
|
|
||||||
|
--- List of spells with additional functions add/remove/clear (modification are allowed only in global scripts or on self).
|
||||||
|
-- @type ActorSpells
|
||||||
|
-- @usage -- print available spells
|
||||||
|
-- local mySpells = types.Actor.spells(self)
|
||||||
|
-- for _, spell in pairs(mySpells) do print(spell.id) end
|
||||||
|
-- @usage -- print available spells (equivalent)
|
||||||
|
-- local mySpells = types.Actor.spells(self)
|
||||||
|
-- for i = 1, #mySpells do print(mySpells[i].id) end
|
||||||
|
-- @usage -- add ALL spells that exist in the world
|
||||||
|
-- local mySpells = types.Actor.spells(self)
|
||||||
|
-- for _, spell in pairs(core.magic.spells) do
|
||||||
|
-- if spell.type == core.magic.SPELL_TYPE.Spell then
|
||||||
|
-- mySpells:add(spell)
|
||||||
|
-- end
|
||||||
|
-- end
|
||||||
|
-- @usage -- add specific spell
|
||||||
|
-- types.Actor.spells(self):add('thunder fist')
|
||||||
|
-- @usage -- check specific spell
|
||||||
|
-- local mySpells = types.Actor.spells(self)
|
||||||
|
-- if mySpells['thunder fist'] then print('I have thunder fist') end
|
||||||
|
|
||||||
|
---
|
||||||
|
-- Add spell (only in global scripts or on self).
|
||||||
|
-- @function [parent=#ActorSpells] add
|
||||||
|
-- @param self
|
||||||
|
-- @param #any spellOrId @{openmw.core#Spell} or string spell id
|
||||||
|
|
||||||
|
---
|
||||||
|
-- Remove spell (only in global scripts or on self).
|
||||||
|
-- @function [parent=#ActorSpells] remove
|
||||||
|
-- @param self
|
||||||
|
-- @param #any spellOrId @{openmw.core#Spell} or string spell id
|
||||||
|
|
||||||
|
---
|
||||||
|
-- Remove all spells (only in global scripts or on self).
|
||||||
|
-- @function [parent=#ActorSpells] clear
|
||||||
|
-- @param self
|
||||||
|
|
||||||
---
|
---
|
||||||
-- @type LevelStat
|
-- @type LevelStat
|
||||||
-- @field #number current The actor's current level.
|
-- @field #number current The actor's current level.
|
||||||
|
@ -631,7 +675,7 @@
|
||||||
-- @field #string speechcraft "speechcraft"
|
-- @field #string speechcraft "speechcraft"
|
||||||
-- @field #string unarmored "unarmored"
|
-- @field #string unarmored "unarmored"
|
||||||
|
|
||||||
--- @{#BookSKILL}
|
--- DEPRECATED, use @{openmw.core#SKILL}
|
||||||
-- @field [parent=#Book] #BookSKILL SKILL
|
-- @field [parent=#Book] #BookSKILL SKILL
|
||||||
|
|
||||||
---
|
---
|
||||||
|
@ -651,7 +695,7 @@
|
||||||
-- @field #string text The text content of the book
|
-- @field #string text The text content of the book
|
||||||
-- @field #number weight
|
-- @field #number weight
|
||||||
-- @field #number value
|
-- @field #number value
|
||||||
-- @field #string skill The skill that this book teaches. See @{#Book.SKILL}
|
-- @field #string skill The skill that this book teaches. See @{openmw.core#SKILL}
|
||||||
-- @field #boolean isScroll
|
-- @field #boolean isScroll
|
||||||
-- @field #number enchantCapacity
|
-- @field #number enchantCapacity
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue