mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-01-25 06:35:30 +00:00
Merge branch 'activate_and_use' into 'master'
Handle Use action in Lua in a similar way to Activate action See merge request OpenMW/openmw!3354
This commit is contained in:
commit
b818414d82
@ -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" };
|
||||
};
|
||||
|
||||
|
@ -19,6 +19,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"
|
||||
@ -316,6 +317,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[@]}"
|
@ -34,6 +34,7 @@ Lua API reference
|
||||
interface_ai
|
||||
interface_camera
|
||||
interface_controls
|
||||
interface_item_usage
|
||||
interface_mwui
|
||||
interface_settings
|
||||
interface_ui
|
||||
@ -64,36 +65,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
|
||||
|
@ -6,6 +6,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.
|
||||
|
||||
@ -16,6 +18,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
|
||||
|
@ -457,36 +457,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
|
||||
============
|
||||
|
34
docs/source/reference/lua-scripting/tables/interfaces.rst
Normal file
34
docs/source/reference/lua-scripting/tables/interfaces.rst
Normal file
@ -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
|
||||
|
||||
|
97
files/data/scripts/omw/usehandlers.lua
Normal file
97
files/data/scripts/omw/usehandlers.lua
Normal file
@ -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…
x
Reference in New Issue
Block a user