Add usehandlers.lua (same approach as activationhandlers.lua)

macos_ci_fix
Petr Mikheev 1 year ago
parent 58aeb81e46
commit ea8692a534

@ -51,6 +51,7 @@ namespace MWBase
virtual void objectTeleported(const MWWorld::Ptr& ptr) = 0;
virtual void itemConsumed(const MWWorld::Ptr& consumable, const MWWorld::Ptr& actor) = 0;
virtual void objectActivated(const MWWorld::Ptr& object, const MWWorld::Ptr& actor) = 0;
virtual void useItem(const MWWorld::Ptr& object, const MWWorld::Ptr& actor) = 0;
virtual void exteriorCreated(MWWorld::CellStore& cell) = 0;
virtual void questUpdated(const ESM::RefId& questId, int stage) = 0;

@ -19,6 +19,7 @@
#include <components/settings/values.hpp>
#include "../mwbase/environment.hpp"
#include "../mwbase/luamanager.hpp"
#include "../mwbase/mechanicsmanager.hpp"
#include "../mwbase/windowmanager.hpp"
#include "../mwbase/world.hpp"
@ -600,7 +601,7 @@ namespace MWGui
}
}
else
useItem(ptr);
MWBase::Environment::get().getLuaManager()->useItem(ptr, MWMechanics::getPlayer());
// If item is ingredient or potion don't stop drag and drop to simplify action of taking more than one 1
// item

@ -65,6 +65,15 @@ namespace MWLua
scripts->onActivated(LObject(actor));
}
void operator()(const OnUseItem& event) const
{
MWWorld::Ptr obj = getPtr(event.mObject);
MWWorld::Ptr actor = getPtr(event.mActor);
if (actor.isEmpty() || obj.isEmpty())
return;
mGlobalScripts.onUseItem(GObject(obj), GObject(actor));
}
void operator()(const OnConsume& event) const
{
MWWorld::Ptr actor = getPtr(event.mActor);

@ -36,6 +36,11 @@ namespace MWLua
ESM::RefNum mActor;
ESM::RefNum mObject;
};
struct OnUseItem
{
ESM::RefNum mActor;
ESM::RefNum mObject;
};
struct OnConsume
{
ESM::RefNum mActor;
@ -45,7 +50,7 @@ namespace MWLua
{
MWWorld::CellStore& mCell;
};
using Event = std::variant<OnActive, OnInactive, OnConsume, OnActivate, OnNewExterior, OnTeleported>;
using Event = std::variant<OnActive, OnInactive, OnConsume, OnActivate, OnUseItem, OnNewExterior, OnTeleported>;
void clear() { mQueue.clear(); }
void addToQueue(Event e) { mQueue.push_back(std::move(e)); }

@ -19,8 +19,16 @@ namespace MWLua
GlobalScripts(LuaUtil::LuaState* lua)
: LuaUtil::ScriptsContainer(lua, "Global")
{
registerEngineHandlers({ &mObjectActiveHandlers, &mActorActiveHandlers, &mItemActiveHandlers,
&mNewGameHandlers, &mPlayerAddedHandlers, &mOnActivateHandlers, &mOnNewExteriorHandlers });
registerEngineHandlers({
&mObjectActiveHandlers,
&mActorActiveHandlers,
&mItemActiveHandlers,
&mNewGameHandlers,
&mPlayerAddedHandlers,
&mOnActivateHandlers,
&mOnUseItemHandlers,
&mOnNewExteriorHandlers,
});
}
void newGameStarted() { callEngineHandlers(mNewGameHandlers); }
@ -32,6 +40,7 @@ namespace MWLua
{
callEngineHandlers(mOnActivateHandlers, obj, actor);
}
void onUseItem(const GObject& obj, const GObject& actor) { callEngineHandlers(mOnUseItemHandlers, obj, actor); }
void onNewExterior(const GCell& cell) { callEngineHandlers(mOnNewExteriorHandlers, cell); }
private:
@ -41,6 +50,7 @@ namespace MWLua
EngineHandlerList mNewGameHandlers{ "onNewGame" };
EngineHandlerList mPlayerAddedHandlers{ "onPlayerAdded" };
EngineHandlerList mOnActivateHandlers{ "onActivate" };
EngineHandlerList mOnUseItemHandlers{ "_onUseItem" };
EngineHandlerList mOnNewExteriorHandlers{ "onNewExterior" };
};

@ -18,6 +18,7 @@
#include "../mwbase/environment.hpp"
#include "../mwbase/statemanager.hpp"
#include "../mwbase/windowmanager.hpp"
#include "../mwworld/action.hpp"
#include "../mwworld/class.hpp"
#include "../mwworld/datetimemanager.hpp"
@ -315,6 +316,21 @@ namespace MWLua
},
"_runStandardActivationAction");
};
api["_runStandardUseAction"] = [context](const GObject& object, const GObject& actor) {
context.mLuaManager->addAction(
[object, actor] {
const MWWorld::Ptr& actorPtr = actor.ptr();
const MWWorld::Ptr& objectPtr = object.ptr();
if (actorPtr == MWBase::Environment::get().getWorld()->getPlayerPtr())
MWBase::Environment::get().getWindowManager()->useItem(objectPtr, true);
else
{
std::unique_ptr<MWWorld::Action> action = objectPtr.getClass().use(objectPtr, true);
action->execute(actorPtr, true);
}
},
"_runStandardUseAction");
};
return LuaUtil::makeReadOnly(api);
}

@ -77,6 +77,10 @@ namespace MWLua
{
mEngineEvents.addToQueue(EngineEvents::OnActivate{ getId(actor), getId(object) });
}
void useItem(const MWWorld::Ptr& object, const MWWorld::Ptr& actor) override
{
mEngineEvents.addToQueue(EngineEvents::OnUseItem{ getId(actor), getId(object) });
}
void exteriorCreated(MWWorld::CellStore& cell) override
{
mEngineEvents.addToQueue(EngineEvents::OnNewExterior{ cell });

@ -7,5 +7,6 @@ paths=(
scripts/omw/mwui/init.lua
scripts/omw/settings/player.lua
scripts/omw/ui.lua
scripts/omw/usehandlers.lua
)
printf '%s\n' "${paths[@]}"

@ -32,6 +32,7 @@ Lua API reference
interface_ai
interface_camera
interface_controls
interface_item_usage
interface_mwui
interface_settings
interface_ui
@ -62,36 +63,6 @@ Sources can be found in ``resources/vfs/openmw_aux``. In theory mods can overrid
.. include:: tables/aux_packages.rst
Interfaces of built-in scripts
------------------------------
**Interfaces of built-in scripts**
.. list-table::
:widths: 20 20 60
* - Interface
- Can be used
- Description
* - :ref:`Activation <Interface Activation>`
- by global scripts
- Allows to extend or override built-in activation mechanics.
* - :ref:`AI <Interface AI>`
- by local scripts
- Control basic AI of NPCs and creatures.
* - :ref:`Camera <Interface Camera>`
- by player scripts
- | Allows to alter behavior of the built-in camera script
| without overriding the script completely.
* - :ref:`Controls <Interface Controls>`
- by player scripts
- | Allows to alter behavior of the built-in script
| that handles player controls.
* - :ref:`Settings <Interface Settings>`
- by player and global scripts
- Save, display and track changes of setting values.
* - :ref:`MWUI <Interface MWUI>`
- by player scripts
- Morrowind-style UI templates.
* - :ref:`UI <Interface UI>`
- by player scripts
- | High-level UI modes interface. Allows to override parts
| of the interface.
.. include:: tables/interfaces.rst

@ -4,6 +4,8 @@ Built-in events
Actor events
------------
**StartAIPackage, RemoveAIPackages**
Any script can send to any actor (except player, for player will be ignored) events ``StartAIPackage`` and ``RemoveAIPackages``.
The effect is equivalent to calling ``interfaces.AI.startPackage`` or ``interfaces.AI.removePackages`` in a local script on this actor.
@ -14,6 +16,17 @@ Examples:
actor:sendEvent('StartAIPackage', {type='Combat', target=self.object})
actor:sendEvent('RemoveAIPackages', 'Pursue')
**UseItem**
Any script can send global event ``UseItem`` with arguments ``object`` and ``actor``.
The actor will use (e.g. equip or consume) the object. The object should be in the actor's inventory.
Example:
.. code-block:: Lua
core.sendGlobalEvent('UseItem', {object = potion, actor = player})
UI events
---------

@ -0,0 +1,6 @@
Interface ItemUsage
===================
.. raw:: html
:file: generated_html/scripts_omw_usehandlers.html

@ -455,36 +455,7 @@ The order in which the scripts are started is important. So if one mod should ov
**Interfaces of built-in scripts**
.. list-table::
:widths: 20 20 60
* - Interface
- Can be used
- Description
* - :ref:`Activation <Interface Activation>`
- by global scripts
- Allows to extend or override built-in activation mechanics.
* - :ref:`AI <Interface AI>`
- by local scripts
- Control basic AI of NPCs and creatures.
* - :ref:`Camera <Interface Camera>`
- by player scripts
- | Allows to alter behavior of the built-in camera script
| without overriding the script completely.
* - :ref:`Controls <Interface Controls>`
- by player scripts
- | Allows to alter behavior of the built-in script
| that handles player controls.
* - :ref:`Settings <Interface Settings>`
- by player and global scripts
- Save, display and track changes of setting values.
* - :ref:`MWUI <Interface MWUI>`
- by player scripts
- Morrowind-style UI templates.
* - :ref:`UI <Interface UI>`
- by player scripts
- | High-level UI modes interface. Allows to override parts
| of the interface.
.. include:: tables/interfaces.rst
Event system
============

@ -0,0 +1,34 @@
.. list-table::
:widths: 20 20 60
* - Interface
- Can be used
- Description
* - :ref:`Activation <Interface Activation>`
- by global scripts
- Allows to extend or override built-in activation mechanics.
* - :ref:`AI <Interface AI>`
- by local scripts
- Control basic AI of NPCs and creatures.
* - :ref:`Camera <Interface Camera>`
- by player scripts
- | Allows to alter behavior of the built-in camera script
| without overriding the script completely.
* - :ref:`Controls <Interface Controls>`
- by player scripts
- | Allows to alter behavior of the built-in script
| that handles player controls.
* - :ref:`ItemUsage <Interface ItemUsage>`
- by global scripts
- | Allows to extend or override built-in item usage
| mechanics.
* - :ref:`Settings <Interface Settings>`
- by player and global scripts
- Save, display and track changes of setting values.
* - :ref:`MWUI <Interface MWUI>`
- by player scripts
- Morrowind-style UI templates.
* - :ref:`UI <Interface UI>`
- by player scripts
- | High-level UI modes interface. Allows to override parts
| of the interface.

@ -90,6 +90,7 @@ set(BUILTIN_DATA_FILES
scripts/omw/mwui/space.lua
scripts/omw/mwui/init.lua
scripts/omw/ui.lua
scripts/omw/usehandlers.lua
shaders/adjustments.omwfx
shaders/bloomlinear.omwfx

@ -8,6 +8,7 @@ PLAYER: scripts/omw/settings/player.lua
# Mechanics
GLOBAL: scripts/omw/activationhandlers.lua
GLOBAL: scripts/omw/cellhandlers.lua
GLOBAL: scripts/omw/usehandlers.lua
PLAYER: scripts/omw/mechanics/playercontroller.lua
PLAYER: scripts/omw/playercontrols.lua
PLAYER: scripts/omw/camera/camera.lua

@ -23,7 +23,6 @@ local handlersPerType = {}
handlersPerType[types.ESM4Door] = { ESM4DoorActivation }
local function onActivate(obj, actor)
types.Actor.activeEffects(actor):remove('invisibility')
local handlers = handlersPerObject[obj.id]
if handlers then
for i = #handlers, 1, -1 do
@ -40,6 +39,7 @@ local function onActivate(obj, actor)
end
end
end
types.Actor.activeEffects(actor):remove('invisibility')
world._runStandardActivationAction(obj, actor)
end

@ -0,0 +1,97 @@
local types = require('openmw.types')
local world = require('openmw.world')
local handlersPerObject = {}
local handlersPerType = {}
local function useItem(obj, actor)
local handlers = handlersPerObject[obj.id]
if handlers then
for i = #handlers, 1, -1 do
if handlers[i](obj, actor) == false then
return -- skip other handlers
end
end
end
handlers = handlersPerType[obj.type]
if handlers then
for i = #handlers, 1, -1 do
if handlers[i](obj, actor) == false then
return -- skip other handlers
end
end
end
world._runStandardUseAction(obj, actor)
end
return {
interfaceName = 'ItemUsage',
---
-- Allows to extend or override built-in item usage mechanics.
-- Note: at the moment it can override item usage in inventory
-- (dragging an item on the character's model), but
--
-- * can't intercept actions performed by mwscripts;
-- * can't intercept actions performed by the AI (i.e. drinking a potion in combat);
-- * can't intercept actions performed via quick keys menu.
-- @module ItemUsage
-- @usage local I = require('openmw.interfaces')
--
-- -- Override Use action (global script).
-- -- Forbid equipping armor with weight > 5
-- I.ItemUsage.addHandlerForType(types.Armor, function(armor, actor)
-- if types.Armor.record(armor).weight > 5 then
-- return false -- disable other handlers
-- end
-- end)
--
-- -- Call Use action (any script).
-- core.sendGlobalEvent('UseItem', {object = armor, actor = player})
interface = {
--- Interface version
-- @field [parent=#ItemUsage] #number version
version = 0,
--- Add new use action handler for a specific object.
-- If `handler(object, actor)` returns false, other handlers for
-- the same object (including type handlers) will be skipped.
-- @function [parent=#ItemUsage] addHandlerForObject
-- @param openmw.core#GameObject obj The object.
-- @param #function handler The handler.
addHandlerForObject = function(obj, handler)
local handlers = handlersPerObject[obj.id]
if handlers == nil then
handlers = {}
handlersPerObject[obj.id] = handlers
end
handlers[#handlers + 1] = handler
end,
--- Add new use action handler for a type of objects.
-- If `handler(object, actor)` returns false, other handlers for
-- the same object (including type handlers) will be skipped.
-- @function [parent=#ItemUsage] addHandlerForType
-- @param #any type A type from the `openmw.types` package.
-- @param #function handler The handler.
addHandlerForType = function(type, handler)
local handlers = handlersPerType[type]
if handlers == nil then
handlers = {}
handlersPerType[type] = handlers
end
handlers[#handlers + 1] = handler
end,
},
engineHandlers = { _onUseItem = useItem },
eventHandlers = {
UseItem = function(data)
if not data.object then
error('UseItem: missing argument "object"')
end
if not data.actor or not types.Actor.objectIsInstance(data.actor) then
error('UseItem: invalid argument "actor"')
end
useItem(data.object, data.actor)
end
}
}

@ -149,6 +149,7 @@
-- Creates a custom record in the world database.
-- Eventually meant to support all records, but the current
-- set of supported types is limited to:
--
-- * @{openmw.types#PotionRecord},
-- * @{openmw.types#ArmorRecord},
-- * @{openmw.types#BookRecord},

Loading…
Cancel
Save