From e65787435142359a4bcae09f3fbb9773dcdff6d1 Mon Sep 17 00:00:00 2001 From: Petr Mikheev Date: Sun, 14 May 2023 11:01:47 +0200 Subject: [PATCH] Lua commands getSelectedSpell/setSelectedSpell --- apps/openmw/mwlua/magicbindings.cpp | 62 +++++++++++++++++++++++++---- apps/openmw/mwlua/types/actor.cpp | 4 +- files/lua_api/openmw/types.lua | 12 ++++++ 3 files changed, 70 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwlua/magicbindings.cpp b/apps/openmw/mwlua/magicbindings.cpp index 6469ac2115..3af9c4967a 100644 --- a/apps/openmw/mwlua/magicbindings.cpp +++ b/apps/openmw/mwlua/magicbindings.cpp @@ -9,10 +9,12 @@ #include #include "../mwbase/environment.hpp" +#include "../mwbase/windowmanager.hpp" #include "../mwbase/world.hpp" #include "../mwmechanics/activespells.hpp" #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/npcstats.hpp" +#include "../mwmechanics/spellutil.hpp" #include "../mwworld/action.hpp" #include "../mwworld/class.hpp" #include "../mwworld/esmstore.hpp" @@ -217,6 +219,13 @@ namespace MWLua void addActorMagicBindings(sol::table& actor, const Context& context) { + auto toSpellId = [](const sol::object& spellOrId) -> ESM::RefId { + if (spellOrId.is()) + return spellOrId.as()->mId; + else + return ESM::RefId::deserializeText(LuaUtil::cast(spellOrId)); + }; + const MWWorld::Store* spellStore = &MWBase::Environment::get().getWorld()->getStore().get(); @@ -226,6 +235,52 @@ namespace MWLua spellsT[sol::meta_function::to_string] = [](const ActorSpells& spells) { return "ActorSpells[" + spells.mActor.object().toString(); }; + actor["getSelectedSpell"] = [spellStore](const Object& o) -> sol::optional { + const MWWorld::Ptr& ptr = o.ptr(); + const MWWorld::Class& cls = ptr.getClass(); + if (!cls.isActor()) + throw std::runtime_error("Actor expected"); + ESM::RefId spellId; + if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + spellId = MWBase::Environment::get().getWindowManager()->getSelectedSpell(); + else + spellId = cls.getCreatureStats(ptr).getSpells().getSelectedSpell(); + if (spellId.empty()) + return sol::nullopt; + else + return spellStore->find(spellId); + }; + actor["setSelectedSpell"] + = [context, spellStore, toSpellId](const SelfObject& o, const sol::object& spellOrId) { + const MWWorld::Ptr& ptr = o.ptr(); + const MWWorld::Class& cls = ptr.getClass(); + if (!cls.isActor()) + throw std::runtime_error("Actor expected"); + ESM::RefId spellId; + if (spellOrId != sol::nil) + { + spellId = toSpellId(spellOrId); + const ESM::Spell* spell = spellStore->find(spellId); + if (spell->mData.mType != ESM::Spell::ST_Spell && spell->mData.mType != ESM::Spell::ST_Power) + throw std::runtime_error("Ability or disease can not be casted: " + spellId.toDebugString()); + } + context.mLuaManager->addAction([obj = Object(ptr), spellId]() { + const MWWorld::Ptr& ptr = obj.ptr(); + auto& stats = ptr.getClass().getCreatureStats(ptr); + if (!stats.getSpells().hasSpell(spellId)) + throw std::runtime_error("Actor doesn't know spell " + spellId.toDebugString()); + if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + { + int chance = 0; + if (!spellId.empty()) + chance = MWMechanics::getSpellSuccessChance(spellId, ptr); + MWBase::Environment::get().getWindowManager()->setSelectedSpell(spellId, chance); + } + else + ptr.getClass().getCreatureStats(ptr).getSpells().setSelectedSpell(spellId); + }); + }; + // #(types.Actor.spells(o)) spellsT[sol::meta_function::length] = [](const ActorSpells& spells) -> size_t { const MWWorld::Ptr& ptr = spells.mActor.ptr(); @@ -253,13 +308,6 @@ namespace MWLua // ipairs(types.Actor.spells(o)) spellsT[sol::meta_function::ipairs] = context.mLua->sol()["ipairsForArray"].template get(); - auto toSpellId = [](const sol::object& spellOrId) -> ESM::RefId { - if (spellOrId.is()) - return spellOrId.as()->mId; - else - return ESM::RefId::deserializeText(LuaUtil::cast(spellOrId)); - }; - // types.Actor.spells(o):add(id) spellsT["add"] = [context, toSpellId](const ActorSpells& spells, const sol::object& spellOrId) { if (spells.mActor.isLObject()) diff --git a/apps/openmw/mwlua/types/actor.cpp b/apps/openmw/mwlua/types/actor.cpp index d9a4b2e13f..bf0866bc0f 100644 --- a/apps/openmw/mwlua/types/actor.cpp +++ b/apps/openmw/mwlua/types/actor.cpp @@ -5,7 +5,6 @@ #include #include -#include #include #include #include @@ -174,6 +173,9 @@ namespace MWLua stats.setDrawState(newDrawState); }; + // TODO + // getSelectedEnchantedItem, setSelectedEnchantedItem + actor["canMove"] = [](const Object& o) { const MWWorld::Class& cls = o.ptr().getClass(); return cls.getMaxSpeed(o.ptr()) > 0; diff --git a/files/lua_api/openmw/types.lua b/files/lua_api/openmw/types.lua index 2e9312c81e..9a06cb53f3 100644 --- a/files/lua_api/openmw/types.lua +++ b/files/lua_api/openmw/types.lua @@ -149,6 +149,18 @@ -- local Actor = require('openmw.types').Actor -- Actor.setEquipment(self, {}) -- unequip all +--- +-- Get currently selected spell +-- @function [parent=#Actor] getSelectedSpell +-- @param openmw.core#GameObject actor +-- @return openmw.core#Spell, nil + +--- +-- Set selected spell +-- @function [parent=#Actor] setSelectedSpell +-- @param openmw.core#GameObject actor +-- @param openmw.core#Spell spell Spell (can be nil) + --- -- Return the spells (@{ActorSpells}) of the given actor. -- @function [parent=#Actor] spells