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>;
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
template <>
|
||||
|
@ -212,6 +300,71 @@ namespace MWLua
|
|||
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::state_view lua = context.sol();
|
||||
|
@ -253,11 +406,13 @@ namespace MWLua
|
|||
// Spell store
|
||||
sol::table spells(lua, sol::create);
|
||||
addRecordFunctionBinding<ESM::Spell>(spells, context);
|
||||
spells["createRecordDraft"] = tableToSpell;
|
||||
magicApi["spells"] = LuaUtil::makeReadOnly(spells);
|
||||
|
||||
// Enchantment store
|
||||
sol::table enchantments(lua, sol::create);
|
||||
addRecordFunctionBinding<ESM::Enchantment>(enchantments, context);
|
||||
enchantments["createRecordDraft"] = tableToEnchantment;
|
||||
magicApi["enchantments"] = LuaUtil::makeReadOnly(enchantments);
|
||||
|
||||
// MagicEffect store
|
||||
|
|
|
@ -3,12 +3,15 @@
|
|||
|
||||
#include <sol/forward.hpp>
|
||||
|
||||
#include <components/esm3/effectlist.hpp>
|
||||
|
||||
#include "context.hpp"
|
||||
|
||||
namespace MWLua
|
||||
{
|
||||
sol::table initCoreMagicBindings(const Context& context);
|
||||
void addActorMagicBindings(sol::table& actor, const Context& context);
|
||||
ESM::IndexedENAMstruct tableToEffectParam(const sol::table& effectTable);
|
||||
}
|
||||
|
||||
#endif // MWLUA_MAGICBINDINGS_H
|
||||
|
|
|
@ -2,7 +2,10 @@
|
|||
|
||||
#include "modelproperty.hpp"
|
||||
|
||||
#include "../magicbindings.hpp"
|
||||
|
||||
#include <components/esm3/loadalch.hpp>
|
||||
#include <components/esm3/loadmgef.hpp>
|
||||
#include <components/lua/luastate.hpp>
|
||||
#include <components/lua/util.hpp>
|
||||
#include <components/misc/resourcehelpers.hpp>
|
||||
|
@ -50,8 +53,17 @@ namespace
|
|||
potion.mEffects.mList.resize(numEffects);
|
||||
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();
|
||||
}
|
||||
return potion;
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
#include <components/esm3/loadmisc.hpp>
|
||||
#include <components/esm3/loadskil.hpp>
|
||||
#include <components/esm3/loadweap.hpp>
|
||||
#include <components/esm3/loadspel.hpp>
|
||||
#include <components/esm3/loadench.hpp>
|
||||
#include <components/lua/luastate.hpp>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
|
@ -192,6 +194,14 @@ namespace MWLua
|
|||
[lua = context.mLua](const ESM::Light& light) -> const ESM::Light* {
|
||||
checkGameInitialized(lua);
|
||||
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) {
|
||||
|
|
|
@ -58,4 +58,18 @@ namespace ESM
|
|||
|| 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
|
||||
|
|
|
@ -30,6 +30,7 @@ namespace ESM
|
|||
{
|
||||
bool operator!=(const IndexedENAMstruct& rhs) const;
|
||||
bool operator==(const IndexedENAMstruct& rhs) const { return !(this->operator!=(rhs)); }
|
||||
void blank();
|
||||
ENAMstruct mData;
|
||||
uint32_t mIndex;
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue