mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-04-28 12:58:00 +03:00
Merge branch 'createenchantrecordsinlua' into 'master'
Some checks are pending
Build and test / Windows (2019) (push) Blocked by required conditions
Build and test / Windows (2022) (push) Blocked by required conditions
Build and test / Ubuntu (push) Waiting to run
Build and test / MacOS (push) Waiting to run
Build and test / Read .env file and expose it as output (push) Waiting to run
Some checks are pending
Build and test / Windows (2019) (push) Blocked by required conditions
Build and test / Windows (2022) (push) Blocked by required conditions
Build and test / Ubuntu (push) Waiting to run
Build and test / MacOS (push) Waiting to run
Build and test / Read .env file and expose it as output (push) Waiting to run
Draft: Add Lua bindings to effects, enchant, spells (#8342) See merge request OpenMW/openmw!4533
This commit is contained in:
commit
3b31fbcd9c
6 changed files with 197 additions and 2 deletions
|
@ -137,6 +137,94 @@ namespace MWLua
|
||||||
using ActorActiveSpells = ActorStore<MWMechanics::ActiveSpells>;
|
using ActorActiveSpells = ActorStore<MWMechanics::ActiveSpells>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
// Populates an enchantment struct from a Lua table.
|
||||||
|
ESM::Enchantment tableToEnchantment(const sol::table& rec)
|
||||||
|
{
|
||||||
|
ESM::Enchantment enchantment;
|
||||||
|
if (rec["template"] != sol::nil)
|
||||||
|
enchantment = LuaUtil::cast<ESM::Enchantment>(rec["template"]);
|
||||||
|
else
|
||||||
|
enchantment.blank();
|
||||||
|
if (rec["autocalcFlag"] != sol::nil)
|
||||||
|
rec["autocalcFlag"]
|
||||||
|
? (enchantment.mData.mFlags | ESM::Enchantment::Autocalc)
|
||||||
|
: (enchantment.mData.mFlags & ~ESM::Enchantment::Autocalc);
|
||||||
|
if (rec["charge"] != sol::nil)
|
||||||
|
enchantment.mData.mCharge = rec["charge"];
|
||||||
|
if (rec["cost"] != sol::nil)
|
||||||
|
enchantment.mData.mCost = rec["cost"];
|
||||||
|
if (rec["effects"] != sol::nil)
|
||||||
|
{
|
||||||
|
sol::table effectsTable = rec["effects"];
|
||||||
|
size_t numEffects = effectsTable.size();
|
||||||
|
enchantment.mEffects.mList.resize(numEffects);
|
||||||
|
for (size_t i = 0; i < numEffects; ++i)
|
||||||
|
{
|
||||||
|
enchantment.mEffects.mList[i] = MWLua::tableToEffectParam(effectsTable[LuaUtil::toLuaIndex(i)]);
|
||||||
|
}
|
||||||
|
enchantment.mEffects.updateIndexes();
|
||||||
|
}
|
||||||
|
if (rec["type"] != sol::nil)
|
||||||
|
{
|
||||||
|
int enchType = rec["type"].get<int>();
|
||||||
|
if (enchType >= 0 && enchType <= ESM::Enchantment::Type::ConstantEffect)
|
||||||
|
enchantment.mData.mType = enchType;
|
||||||
|
else
|
||||||
|
throw std::runtime_error("Invalid Enchantment Type provided: " + std::to_string(enchType));
|
||||||
|
}
|
||||||
|
|
||||||
|
return enchantment;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Populates a spell struct from a Lua table.
|
||||||
|
ESM::Spell tableToSpell(const sol::table& rec)
|
||||||
|
{
|
||||||
|
ESM::Spell spell;
|
||||||
|
if (rec["template"] != sol::nil)
|
||||||
|
spell = LuaUtil::cast<ESM::Spell>(rec["template"]);
|
||||||
|
else
|
||||||
|
spell.blank();
|
||||||
|
if (rec["alwaysSucceedFlag"] != sol::nil)
|
||||||
|
rec["alwaysSucceedFlag"]
|
||||||
|
? (spell.mData.mFlags | ESM::Spell::F_Always)
|
||||||
|
: (spell.mData.mFlags & ~ESM::Spell::F_Always);
|
||||||
|
if (rec["autocalcFlag"] != sol::nil)
|
||||||
|
rec["autocalcFlag"]
|
||||||
|
? (spell.mData.mFlags | ESM::Spell::F_Autocalc)
|
||||||
|
: (spell.mData.mFlags & ~ESM::Spell::F_Autocalc);
|
||||||
|
if (rec["starterSpellFlag"] != sol::nil)
|
||||||
|
rec["starterSpellFlag"]
|
||||||
|
? (spell.mData.mFlags | ESM::Spell::F_PCStart)
|
||||||
|
: (spell.mData.mFlags & ~ESM::Spell::F_PCStart);
|
||||||
|
if (rec["cost"] != sol::nil)
|
||||||
|
spell.mData.mCost = rec["cost"];
|
||||||
|
if (rec["name"] != sol::nil)
|
||||||
|
spell.mName = rec["name"];
|
||||||
|
if (rec["effects"] != sol::nil)
|
||||||
|
{
|
||||||
|
sol::table effectsTable = rec["effects"];
|
||||||
|
size_t numEffects = effectsTable.size();
|
||||||
|
spell.mEffects.mList.resize(numEffects);
|
||||||
|
for (size_t i = 0; i < numEffects; ++i)
|
||||||
|
{
|
||||||
|
spell.mEffects.mList[i] = MWLua::tableToEffectParam(effectsTable[LuaUtil::toLuaIndex(i)]);
|
||||||
|
}
|
||||||
|
spell.mEffects.updateIndexes();
|
||||||
|
}
|
||||||
|
if (rec["type"] != sol::nil)
|
||||||
|
{
|
||||||
|
int spellType = rec["type"].get<int>();
|
||||||
|
if (spellType >= 0 && spellType <= ESM::Spell::ST_Power)
|
||||||
|
spell.mData.mType = spellType;
|
||||||
|
else
|
||||||
|
throw std::runtime_error("Invalid Spell Type provided: " + std::to_string(spellType));
|
||||||
|
}
|
||||||
|
return spell;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
namespace sol
|
namespace sol
|
||||||
{
|
{
|
||||||
template <>
|
template <>
|
||||||
|
@ -212,6 +300,71 @@ namespace MWLua
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Creates the IndexedENAMstruct based on the table, validating provided data and ignoring unrequired fields
|
||||||
|
ESM::IndexedENAMstruct tableToEffectParam(const sol::table& effectTable)
|
||||||
|
{
|
||||||
|
ESM::IndexedENAMstruct effect;
|
||||||
|
effect.blank();
|
||||||
|
if (effectTable["id"] == sol::nil)
|
||||||
|
throw std::runtime_error("Spell effect id expected");
|
||||||
|
|
||||||
|
int effectId = ESM::MagicEffect::indexNameToIndex(effectTable["id"].get<std::string_view>());
|
||||||
|
if (effectId == -1)
|
||||||
|
throw std::runtime_error("Invalid effect id provided: " + effectTable["id"].get<std::string>());
|
||||||
|
effect.mData.mEffectID = effectId;
|
||||||
|
const ESM::MagicEffect* const magicEffect = MWBase::Environment::get()
|
||||||
|
.getWorld() -> getStore()
|
||||||
|
.get<ESM::MagicEffect>()
|
||||||
|
.find(effectId);
|
||||||
|
if (magicEffect->mData.mFlags & ESM::MagicEffect::TargetSkill)
|
||||||
|
{
|
||||||
|
if (effectTable["affectedSkill"] == sol::nil)
|
||||||
|
throw std::runtime_error("Expected affectedSkill for " + effectTable["id"].get<std::string>());
|
||||||
|
int skillId = ESM::Skill::refIdToIndex(
|
||||||
|
ESM::RefId::deserializeText(effectTable["affectedSkill"].get<std::string_view>()));
|
||||||
|
if (skillId == -1)
|
||||||
|
throw std::runtime_error(
|
||||||
|
"Invalid affectedSkill provided: " + effectTable["affectedSkill"].get<std::string>());
|
||||||
|
effect.mData.mSkill = skillId;
|
||||||
|
}
|
||||||
|
if (magicEffect->mData.mFlags & ESM::MagicEffect::TargetAttribute)
|
||||||
|
{
|
||||||
|
if (effectTable["affectedAttribute"] == sol::nil)
|
||||||
|
throw std::runtime_error("Expected affectedAttribute for " + effectTable["id"].get<std::string>());
|
||||||
|
int attributeId = ESM::Attribute::refIdToIndex(
|
||||||
|
ESM::RefId::deserializeText(effectTable["affectedAttribute"].get<std::string_view>()));
|
||||||
|
if (attributeId == -1)
|
||||||
|
throw std::runtime_error(
|
||||||
|
"Invalid affectedAttribute provided: " + effectTable["affectedAttribute"].get<std::string>());
|
||||||
|
effect.mData.mAttribute = attributeId;
|
||||||
|
}
|
||||||
|
if (effectTable["range"] != sol::nil)
|
||||||
|
{
|
||||||
|
effect.mData.mRange = effectTable["range"].get<int32_t>();
|
||||||
|
if ((effect.mData.mRange == ESM::RT_Self) and !(magicEffect->mData.mFlags & ESM::MagicEffect::CastSelf))
|
||||||
|
throw std::runtime_error(effectTable["id"].get<std::string>() + " cannot be casted on self");
|
||||||
|
if ((effect.mData.mRange == ESM::RT_Touch) and !(magicEffect->mData.mFlags & ESM::MagicEffect::CastTouch))
|
||||||
|
throw std::runtime_error(effectTable["id"].get<std::string>() + " cannot be casted on touch");
|
||||||
|
if ((effect.mData.mRange == ESM::RT_Target) and !(magicEffect->mData.mFlags & ESM::MagicEffect::CastTarget))
|
||||||
|
throw std::runtime_error(effectTable["id"].get<std::string>() + " cannot be casted on target");
|
||||||
|
}
|
||||||
|
if (effectTable["area"] != sol::nil) // Should area be only available to Touch and or Target ?
|
||||||
|
effect.mData.mArea = effectTable["area"].get<int32_t>();
|
||||||
|
if (!(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration))
|
||||||
|
if (effectTable["duration"] != sol::nil)
|
||||||
|
effect.mData.mDuration = effectTable["duration"].get<int32_t>();
|
||||||
|
if (!(magicEffect->mData.mFlags & ESM::MagicEffect::NoMagnitude))
|
||||||
|
{
|
||||||
|
if (effectTable["magnitudeMin"] != sol::nil)
|
||||||
|
effect.mData.mMagnMin = effectTable["magnitudeMin"].get<int32_t>();
|
||||||
|
if (effectTable["magnitudeMax"] != sol::nil)
|
||||||
|
effect.mData.mMagnMax = effectTable["magnitudeMax"].get<int32_t>();
|
||||||
|
if (effect.mData.mMagnMax < effect.mData.mMagnMin)
|
||||||
|
throw std::runtime_error("magnitudeMax cannot be lower than magnitudeMin");
|
||||||
|
}
|
||||||
|
return effect;
|
||||||
|
}
|
||||||
|
|
||||||
sol::table initCoreMagicBindings(const Context& context)
|
sol::table initCoreMagicBindings(const Context& context)
|
||||||
{
|
{
|
||||||
sol::state_view lua = context.sol();
|
sol::state_view lua = context.sol();
|
||||||
|
@ -253,11 +406,13 @@ namespace MWLua
|
||||||
// Spell store
|
// Spell store
|
||||||
sol::table spells(lua, sol::create);
|
sol::table spells(lua, sol::create);
|
||||||
addRecordFunctionBinding<ESM::Spell>(spells, context);
|
addRecordFunctionBinding<ESM::Spell>(spells, context);
|
||||||
|
spells["createRecordDraft"] = tableToSpell;
|
||||||
magicApi["spells"] = LuaUtil::makeReadOnly(spells);
|
magicApi["spells"] = LuaUtil::makeReadOnly(spells);
|
||||||
|
|
||||||
// Enchantment store
|
// Enchantment store
|
||||||
sol::table enchantments(lua, sol::create);
|
sol::table enchantments(lua, sol::create);
|
||||||
addRecordFunctionBinding<ESM::Enchantment>(enchantments, context);
|
addRecordFunctionBinding<ESM::Enchantment>(enchantments, context);
|
||||||
|
enchantments["createRecordDraft"] = tableToEnchantment;
|
||||||
magicApi["enchantments"] = LuaUtil::makeReadOnly(enchantments);
|
magicApi["enchantments"] = LuaUtil::makeReadOnly(enchantments);
|
||||||
|
|
||||||
// MagicEffect store
|
// MagicEffect store
|
||||||
|
|
|
@ -3,12 +3,15 @@
|
||||||
|
|
||||||
#include <sol/forward.hpp>
|
#include <sol/forward.hpp>
|
||||||
|
|
||||||
|
#include <components/esm3/effectlist.hpp>
|
||||||
|
|
||||||
#include "context.hpp"
|
#include "context.hpp"
|
||||||
|
|
||||||
namespace MWLua
|
namespace MWLua
|
||||||
{
|
{
|
||||||
sol::table initCoreMagicBindings(const Context& context);
|
sol::table initCoreMagicBindings(const Context& context);
|
||||||
void addActorMagicBindings(sol::table& actor, const Context& context);
|
void addActorMagicBindings(sol::table& actor, const Context& context);
|
||||||
|
ESM::IndexedENAMstruct tableToEffectParam(const sol::table& effectTable);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // MWLUA_MAGICBINDINGS_H
|
#endif // MWLUA_MAGICBINDINGS_H
|
||||||
|
|
|
@ -2,7 +2,10 @@
|
||||||
|
|
||||||
#include "modelproperty.hpp"
|
#include "modelproperty.hpp"
|
||||||
|
|
||||||
|
#include "../magicbindings.hpp"
|
||||||
|
|
||||||
#include <components/esm3/loadalch.hpp>
|
#include <components/esm3/loadalch.hpp>
|
||||||
|
#include <components/esm3/loadmgef.hpp>
|
||||||
#include <components/lua/luastate.hpp>
|
#include <components/lua/luastate.hpp>
|
||||||
#include <components/lua/util.hpp>
|
#include <components/lua/util.hpp>
|
||||||
#include <components/misc/resourcehelpers.hpp>
|
#include <components/misc/resourcehelpers.hpp>
|
||||||
|
@ -50,8 +53,17 @@ namespace
|
||||||
potion.mEffects.mList.resize(numEffects);
|
potion.mEffects.mList.resize(numEffects);
|
||||||
for (size_t i = 0; i < numEffects; ++i)
|
for (size_t i = 0; i < numEffects; ++i)
|
||||||
{
|
{
|
||||||
potion.mEffects.mList[i] = LuaUtil::cast<ESM::IndexedENAMstruct>(effectsTable[LuaUtil::toLuaIndex(i)]);
|
sol::object element = effectsTable[LuaUtil::toLuaIndex(i)];
|
||||||
}
|
if (element.is<ESM::IndexedENAMstruct>()) // It can be casted (extracted from another magic thing)
|
||||||
|
{
|
||||||
|
potion.mEffects.mList[i]
|
||||||
|
= LuaUtil::cast<ESM::IndexedENAMstruct>(effectsTable[LuaUtil::toLuaIndex(i)]);
|
||||||
|
}
|
||||||
|
else // Recreates from a table
|
||||||
|
{
|
||||||
|
potion.mEffects.mList[i] = MWLua::tableToEffectParam(effectsTable[LuaUtil::toLuaIndex(i)]);
|
||||||
|
}
|
||||||
|
} // Updates the index in the IndexedENAMstruct
|
||||||
potion.mEffects.updateIndexes();
|
potion.mEffects.updateIndexes();
|
||||||
}
|
}
|
||||||
return potion;
|
return potion;
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
#include <components/esm3/loadmisc.hpp>
|
#include <components/esm3/loadmisc.hpp>
|
||||||
#include <components/esm3/loadskil.hpp>
|
#include <components/esm3/loadskil.hpp>
|
||||||
#include <components/esm3/loadweap.hpp>
|
#include <components/esm3/loadweap.hpp>
|
||||||
|
#include <components/esm3/loadspel.hpp>
|
||||||
|
#include <components/esm3/loadench.hpp>
|
||||||
#include <components/lua/luastate.hpp>
|
#include <components/lua/luastate.hpp>
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
|
@ -192,6 +194,14 @@ namespace MWLua
|
||||||
[lua = context.mLua](const ESM::Light& light) -> const ESM::Light* {
|
[lua = context.mLua](const ESM::Light& light) -> const ESM::Light* {
|
||||||
checkGameInitialized(lua);
|
checkGameInitialized(lua);
|
||||||
return MWBase::Environment::get().getESMStore()->insert(light);
|
return MWBase::Environment::get().getESMStore()->insert(light);
|
||||||
|
},
|
||||||
|
[lua = context.mLua](const ESM::Enchantment& ench) -> const ESM::Enchantment* {
|
||||||
|
checkGameInitialized(lua);
|
||||||
|
return MWBase::Environment::get().getESMStore()->insert(ench);
|
||||||
|
},
|
||||||
|
[lua = context.mLua](const ESM::Spell& spell) -> const ESM::Spell* {
|
||||||
|
checkGameInitialized(lua);
|
||||||
|
return MWBase::Environment::get().getESMStore()->insert(spell);
|
||||||
});
|
});
|
||||||
|
|
||||||
api["_runStandardActivationAction"] = [context](const GObject& object, const GObject& actor) {
|
api["_runStandardActivationAction"] = [context](const GObject& object, const GObject& actor) {
|
||||||
|
|
|
@ -58,4 +58,18 @@ namespace ESM
|
||||||
|| mData.mMagnMax != rhs.mData.mMagnMax || mData.mDuration != rhs.mData.mDuration;
|
|| mData.mMagnMax != rhs.mData.mMagnMax || mData.mDuration != rhs.mData.mDuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Initialize a default, blank effect
|
||||||
|
void IndexedENAMstruct::blank()
|
||||||
|
{
|
||||||
|
mData.mEffectID = 0;
|
||||||
|
mData.mArea = 0;
|
||||||
|
mData.mRange = 0;
|
||||||
|
mData.mSkill = -1;
|
||||||
|
mData.mAttribute = -1;
|
||||||
|
mData.mMagnMax = 0;
|
||||||
|
mData.mMagnMin = 0;
|
||||||
|
mData.mDuration = 0;
|
||||||
|
mIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
} // end namespace
|
} // end namespace
|
||||||
|
|
|
@ -30,6 +30,7 @@ namespace ESM
|
||||||
{
|
{
|
||||||
bool operator!=(const IndexedENAMstruct& rhs) const;
|
bool operator!=(const IndexedENAMstruct& rhs) const;
|
||||||
bool operator==(const IndexedENAMstruct& rhs) const { return !(this->operator!=(rhs)); }
|
bool operator==(const IndexedENAMstruct& rhs) const { return !(this->operator!=(rhs)); }
|
||||||
|
void blank();
|
||||||
ENAMstruct mData;
|
ENAMstruct mData;
|
||||||
uint32_t mIndex;
|
uint32_t mIndex;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue