Lua command `object:activateBy(actor)` and handler `onActivate`

C++20
Petr Mikheev 3 years ago committed by uramer
parent 03f1b1a082
commit 47c37e5849

@ -218,6 +218,7 @@ Programmers
tlmullis
tri4ng1e
Thoronador
Tobias Tribble (zackogenic)
Tom Lowe (Vulpen)
Tom Mason (wheybags)
Torben Leif Carrington (TorbenC)
@ -234,7 +235,6 @@ Programmers
Yuri Krupenin
zelurker
Noah Gooder
Documentation
-------------

@ -36,6 +36,7 @@ namespace MWBase
virtual void objectAddedToScene(const MWWorld::Ptr& ptr) = 0;
virtual void objectRemovedFromScene(const MWWorld::Ptr& ptr) = 0;
virtual void appliedToObject(const MWWorld::Ptr& toPtr, std::string_view recordId, const MWWorld::Ptr& fromPtr) = 0;
virtual void objectActivated(const MWWorld::Ptr& object, const MWWorld::Ptr& actor) = 0;
// TODO: notify LuaManager about other events
// virtual void objectOnHit(const MWWorld::Ptr &ptr, float damage, bool ishealth, const MWWorld::Ptr &object,
// const MWWorld::Ptr &attacker, const osg::Vec3f &hitPosition, bool successful) = 0;

@ -6,10 +6,13 @@
#include <components/lua/luastate.hpp>
#include <components/settings/settings.hpp>
#include "../mwworld/cellstore.hpp"
#include "../mwworld/class.hpp"
#include "../mwworld/inventorystore.hpp"
#include "../mwworld/player.hpp"
#include <apps/openmw/mwbase/luamanager.hpp>
#include <apps/openmw/mwworld/action.hpp>
#include <apps/openmw/mwworld/cellstore.hpp>
#include <apps/openmw/mwworld/class.hpp>
#include <apps/openmw/mwworld/inventorystore.hpp>
#include <apps/openmw/mwworld/player.hpp>
namespace MWLua
{
@ -145,4 +148,24 @@ namespace MWLua
tryEquipToSlot(anySlot, item);
}
void ActivateAction::apply(WorldView& worldView) const
{
MWWorld::Ptr object = worldView.getObjectRegistry()->getPtr(mObject, true);
if (object.isEmpty())
throw std::runtime_error(std::string("Object not found: " + idToString(mObject)));
MWWorld::Ptr actor = worldView.getObjectRegistry()->getPtr(mActor, true);
if (actor.isEmpty())
throw std::runtime_error(std::string("Actor not found: " + idToString(mActor)));
MWBase::Environment::get().getLuaManager()->objectActivated(object, actor);
std::shared_ptr<MWWorld::Action> action = object.getClass().activate(object, actor);
action->execute(actor);
}
std::string ActivateAction::toString() const
{
return std::string("ActivateAction object=") + idToString(mObject) +
std::string(" actor=") + idToString(mActor);
}
}

@ -65,6 +65,20 @@ namespace MWLua
Equipment mEquipment;
};
class ActivateAction final : public Action
{
public:
ActivateAction(LuaUtil::LuaState* state, ObjectId object, ObjectId actor)
: Action(state), mObject(object), mActor(actor) {}
void apply(WorldView&) const override;
std::string toString() const override;
private:
ObjectId mObject;
ObjectId mActor;
};
}
#endif // MWLUA_ACTIONS_H

@ -88,7 +88,7 @@ namespace MWLua
: LuaUtil::ScriptsContainer(lua, "L" + idToString(obj.id()), autoStartMode), mData(obj)
{
this->addPackage("openmw.self", sol::make_object(lua->sol(), &mData));
registerEngineHandlers({&mOnActiveHandlers, &mOnInactiveHandlers, &mOnConsumeHandlers});
registerEngineHandlers({&mOnActiveHandlers, &mOnInactiveHandlers, &mOnConsumeHandlers, &mOnActivatedHandlers});
}
void LocalScripts::receiveEngineEvent(const EngineEvent& event)
@ -106,6 +106,10 @@ namespace MWLua
mData.mIsActive = false;
callEngineHandlers(mOnInactiveHandlers);
}
else if constexpr (std::is_same_v<EventT, OnActivated>)
{
callEngineHandlers(mOnActivatedHandlers, arg.mActivatingActor);
}
else
{
static_assert(std::is_same_v<EventT, OnConsume>);

@ -33,11 +33,15 @@ namespace MWLua
struct OnActive {};
struct OnInactive {};
struct OnActivated
{
LObject mActivatingActor;
};
struct OnConsume
{
std::string mRecordId;
};
using EngineEvent = std::variant<OnActive, OnInactive, OnConsume>;
using EngineEvent = std::variant<OnActive, OnInactive, OnConsume, OnActivated>;
void receiveEngineEvent(const EngineEvent&);
@ -48,6 +52,7 @@ namespace MWLua
EngineHandlerList mOnActiveHandlers{"onActive"};
EngineHandlerList mOnInactiveHandlers{"onInactive"};
EngineHandlerList mOnConsumeHandlers{"onConsume"};
EngineHandlerList mOnActivatedHandlers{"onActivated"};
};
}

@ -352,6 +352,11 @@ namespace MWLua
mLocalEngineEvents.push_back({getId(toPtr), LocalScripts::OnConsume{std::string(recordId)}});
}
void LuaManager::objectActivated(const MWWorld::Ptr& object, const MWWorld::Ptr& actor)
{
mLocalEngineEvents.push_back({getId(object), LocalScripts::OnActivated{LObject(getId(actor), mWorldView.getObjectRegistry())}});
}
MWBase::LuaManager::ActorControls* LuaManager::getActorControls(const MWWorld::Ptr& ptr) const
{
LocalScripts* localScripts = ptr.getRefData().getLuaScripts();

@ -49,6 +49,7 @@ namespace MWLua
void deregisterObject(const MWWorld::Ptr& ptr) override;
void inputEvent(const InputEvent& event) override { mInputEvents.push_back(event); }
void appliedToObject(const MWWorld::Ptr& toPtr, std::string_view recordId, const MWWorld::Ptr& fromPtr) override;
void objectActivated(const MWWorld::Ptr& object, const MWWorld::Ptr& actor) override;
MWBase::LuaManager::ActorControls* getActorControls(const MWWorld::Ptr&) const override;

@ -137,6 +137,14 @@ namespace MWLua
const MWWorld::Class& cls = o.ptr().getClass();
return cls.getWalkSpeed(o.ptr());
};
objectT["activateBy"] = [context](const ObjectT& o, const ObjectT& actor)
{
uint32_t esmRecordType = actor.ptr().getType();
if (esmRecordType != ESM::REC_CREA && esmRecordType != ESM::REC_NPC_)
throw std::runtime_error("The argument of `activateBy` must be an actor who activates the object. Got: " +
ptrToString(actor.ptr()));
context.mLuaManager->addAction(std::make_unique<ActivateAction>(context.mLua, o.id(), actor.id()));
};
if constexpr (std::is_same_v<ObjectT, GObject>)
{ // Only for global scripts

@ -12,6 +12,7 @@
#include "../mwbase/scriptmanager.hpp"
#include "../mwbase/windowmanager.hpp"
#include "../mwbase/inputmanager.hpp"
#include "../mwbase/luamanager.hpp"
#include "../mwworld/action.hpp"
#include "../mwworld/class.hpp"
@ -417,6 +418,7 @@ namespace MWScript
void InterpreterContext::executeActivation(const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor)
{
MWBase::Environment::get().getLuaManager()->objectActivated(ptr, actor);
std::shared_ptr<MWWorld::Action> action = (ptr.getClass().activate(ptr, actor));
action->execute (actor);
if (action->getTarget() != MWWorld::Ptr() && action->getTarget() != ptr)

@ -3827,7 +3827,8 @@ namespace MWWorld
if (object.getRefData().activate())
{
std::shared_ptr<MWWorld::Action> action = (object.getClass().activate(object, actor));
MWBase::Environment::get().getLuaManager()->objectActivated(object, actor);
std::shared_ptr<MWWorld::Action> action = object.getClass().activate(object, actor);
action->execute (actor);
}
}

@ -43,6 +43,12 @@ Engine handler is a function defined by a script, that can be called by the engi
| | | can not access anything nearby, but it is possible to send |
| | | an event to global scripts. |
+----------------------------------+----------------------------------------------------------------------+
| onActivated(actor) | | Called on an object when an actor activates it. Note that picking |
| | | up an item is also an activation and works this way: (1) a copy of |
| | | the item is placed to the actor's inventory, (2) count of |
| | | the original item is set to zero, (3) and only then onActivated is |
| | | called on the original item, so self.count is already zero. |
+----------------------------------+----------------------------------------------------------------------+
| onConsume(recordId) | | Called if `recordId` (e.g. a potion) is consumed. |
+----------------------------------+----------------------------------------------------------------------+
| **Only for local scripts attached to a player** |

@ -217,6 +217,14 @@
-- @param #string eventName
-- @param eventData
-------------------------------------------------------------------------------
-- Activate the object.
-- @function [parent=#GameObject] activateBy
-- @param self
-- @param #GameObject actor The actor who activates the object
-- @usage local self = require('openmw.self')
-- object:activateBy(self)
-------------------------------------------------------------------------------
-- Returns `true` if the item is equipped on the object.
-- @function [parent=#GameObject] isEquipped

Loading…
Cancel
Save