diff --git a/doc/en/scripting/builtins/libhud.md b/doc/en/scripting/builtins/libhud.md
index 1d6264b2d..550659ccc 100644
--- a/doc/en/scripting/builtins/libhud.md
+++ b/doc/en/scripting/builtins/libhud.md
@@ -57,6 +57,10 @@ hud.get_block_inventory() -> int
-- Gives the ID of the second open inventory (block, virtual inventory...) or 0.
hud.get_second_inventory() -> int
+-- Get the inventory ID of exchange item (grabbed item in inventory) or 0.
+-- It has only one slot - 0
+hud.get_exchange_inventory() -> int
+
-- Gives the ID of the player that the UI is bound to.
hud.get_player() -> int
diff --git a/doc/ru/scripting/builtins/libhud.md b/doc/ru/scripting/builtins/libhud.md
index bad0e93c6..7a93c93e4 100644
--- a/doc/ru/scripting/builtins/libhud.md
+++ b/doc/ru/scripting/builtins/libhud.md
@@ -58,6 +58,11 @@ hud.get_block_inventory() -> int
-- Дает ID второго открытого инвентаря (блок, виртуальный инвентарь...) или 0.
hud.get_second_inventory() -> int
+-- Получить ID инвентаря, в котором находится предмет во время
+-- его перемещения в инвентаре, или 0 если его не существует.
+-- Имеет единственный слот - 0
+hud.get_exchange_inventory() -> int
+
-- Дает ID игрока, к которому привязан пользовательский интерфейс.
hud.get_player() -> int
@@ -81,4 +86,4 @@ hud.set_allow_pause(flag: boolean)
-- Функция, управляющая именованным скелетом 'hand' (см. gfx.skeletons)
hud.hand_controller: function()
-```
\ No newline at end of file
+```
diff --git a/res/content/base/modules/util.lua b/res/content/base/modules/util.lua
index 874e6d3d6..4d25ccb91 100644
--- a/res/content/base/modules/util.lua
+++ b/res/content/base/modules/util.lua
@@ -1,5 +1,44 @@
local util = {}
+local DROP_FORCE = 8
+local DROP_INIT_VEL = {0, 3, 0}
+
+---@param mode integer 0 - whole stack, 1 - single item, 2 - dupe whole stack
+function util.drop_from_slot(invid, slot, mode)
+ if invid == 0 then
+ return
+ end
+ local pid = hud.get_player()
+ if mode == 2 and not player.is_infinite_items(pid) then
+ return
+ end
+ local itemid, itemcount = inventory.get(invid, slot)
+ if itemid == 0 then
+ return
+ end
+
+ local drop_itemcount = 1
+ if mode == 0 then
+ drop_itemcount = itemcount
+ end
+ if mode == 2 then
+ drop_itemcount = item.stack_size(itemid)
+ else
+ inventory.set(invid, slot, itemid, itemcount - drop_itemcount)
+ end
+
+ local data = inventory.get_all_data(invid, slot)
+ local pvel = { player.get_vel(pid) }
+ local ppos = vec3.add({ player.get_pos(pid) }, { 0, 0.7, 0 })
+ local throw_force = vec3.mul(player.get_dir(pid), DROP_FORCE)
+ local drop = util.drop(ppos, itemid, drop_itemcount, data, 1.5)
+ if not drop then
+ return
+ end
+ local velocity = vec3.add(throw_force, vec3.add(pvel, DROP_INIT_VEL))
+ drop.rigidbody:set_vel(velocity)
+end
+
function util.drop(ppos, itemid, count, data, pickup_delay)
if itemid == 0 or not itemid then
return nil
diff --git a/res/content/base/scripts/hud.lua b/res/content/base/scripts/hud.lua
index 0ec427c11..d0e3d1532 100644
--- a/res/content/base/scripts/hud.lua
+++ b/res/content/base/scripts/hud.lua
@@ -1,31 +1,21 @@
local base_util = require "util"
-local DROP_FORCE = 8
-local DROP_INIT_VEL = {0, 3, 0}
-
function on_hud_open()
- input.add_callback("player.drop", function ()
+ events.on("core:drop_outside_inventory", function(mode)
+ local invid = hud.get_exchange_inventory()
+ base_util.drop_from_slot(invid, 0, mode)
+ end)
+ input.add_callback("player.drop", function()
if hud.is_paused() or hud.is_inventory_open() then
return
end
local pid = hud.get_player()
local invid, slot = player.get_inventory(pid)
- local itemid, itemcount = inventory.get(invid, slot)
- if itemid == 0 then
- return
+ local mode = 1
+ if input.is_pressed("key:left-ctrl") or input.is_pressed("key:right-ctrl") then
+ mode = 0
end
- local data = inventory.get_all_data(invid, slot)
- inventory.set(invid, slot, itemid, itemcount-1)
-
- local pvel = {player.get_vel(pid)}
- local ppos = vec3.add({player.get_pos(pid)}, {0, 0.7, 0})
- local throw_force = vec3.mul(player.get_dir(pid), DROP_FORCE)
- local drop = base_util.drop(ppos, itemid, 1, data, 1.5)
- if not drop then
- return
- end
- local velocity = vec3.add(throw_force, vec3.add(pvel, DROP_INIT_VEL))
- drop.rigidbody:set_vel(velocity)
+ base_util.drop_from_slot(invid, slot, mode)
end)
rules.create("do-loot-non-player", true)
end
diff --git a/src/frontend/hud.cpp b/src/frontend/hud.cpp
index 1aa03436b..08a4b8455 100644
--- a/src/frontend/hud.cpp
+++ b/src/frontend/hud.cpp
@@ -174,6 +174,15 @@ Hud::Hud(Engine& engine, LevelFrontend& frontend, Player& player)
gui,
""
);
+
+ inventoryDropArea = guiutil::create(
+ gui,
+ R"()"
+ );
uicamera = std::make_unique(glm::vec3(), 1);
uicamera->perspective = false;
@@ -188,6 +197,7 @@ Hud::Hud(Engine& engine, LevelFrontend& frontend, Player& player)
gui.add(debugPanel);
gui.add(darkOverlay);
+ gui.add(inventoryDropArea);
gui.add(hotbarView);
gui.add(contentAccessPanel);
@@ -213,6 +223,7 @@ Hud::~Hud() {
}
gui.remove(hotbarView);
gui.remove(darkOverlay);
+ gui.remove(inventoryDropArea);
gui.remove(contentAccessPanel);
gui.remove(debugPanel);
}
@@ -358,6 +369,7 @@ void Hud::update(bool visible) {
contentAccess->setMinSize(glm::vec2(1, windowSize.y));
hotbarView->setVisible(visible && !(secondUI && !inventoryView));
darkOverlay->setVisible(isMenuOpen);
+ inventoryDropArea->setVisible(inventoryOpen);
menu.setVisible(isMenuOpen);
if (visible) {
@@ -739,6 +751,10 @@ std::shared_ptr Hud::getSecondInventory() {
return nullptr;
}
+std::shared_ptr Hud::getExchangeInventory() {
+ return exchangeSlotInv;
+}
+
bool Hud::isContentAccess() const {
return showContentPanel;
}
diff --git a/src/frontend/hud.hpp b/src/frontend/hud.hpp
index f80c36369..f40a53581 100644
--- a/src/frontend/hud.hpp
+++ b/src/frontend/hud.hpp
@@ -93,6 +93,8 @@ class Hud : public util::ObjectsKeeper {
std::shared_ptr debugPanel;
/// @brief Overlay used in pause mode
std::shared_ptr darkOverlay;
+ /// @brief Overlay used in inventory
+ std::shared_ptr inventoryDropArea;
/// @brief Inventories interaction agent (grabbed item)
std::shared_ptr exchangeSlot;
/// @brief Exchange slot inventory (1 slot only)
@@ -207,6 +209,8 @@ public:
std::shared_ptr getSecondInventory();
+ std::shared_ptr getExchangeInventory();
+
bool isContentAccess() const;
void setContentAccess(bool flag);
diff --git a/src/graphics/ui/GUI.cpp b/src/graphics/ui/GUI.cpp
index 8bfe3a341..944c32fb5 100644
--- a/src/graphics/ui/GUI.cpp
+++ b/src/graphics/ui/GUI.cpp
@@ -14,7 +14,6 @@
#include "frontend/UiDocument.hpp"
#include "frontend/locale.hpp"
#include "graphics/core/Batch2D.hpp"
-#include "graphics/core/LineBatch.hpp"
#include "graphics/core/Shader.hpp"
#include "graphics/core/Font.hpp"
#include "graphics/core/DrawContext.hpp"
diff --git a/src/graphics/ui/elements/InventoryView.cpp b/src/graphics/ui/elements/InventoryView.cpp
index 144d80397..395c8d34e 100644
--- a/src/graphics/ui/elements/InventoryView.cpp
+++ b/src/graphics/ui/elements/InventoryView.cpp
@@ -12,11 +12,8 @@
#include "graphics/core/Batch2D.hpp"
#include "graphics/core/DrawContext.hpp"
#include "graphics/core/Font.hpp"
-#include "graphics/core/Shader.hpp"
-#include "graphics/core/Texture.hpp"
#include "graphics/render/BlocksPreview.hpp"
#include "graphics/ui/GUI.hpp"
-#include "items/Inventories.hpp"
#include "items/Inventory.hpp"
#include "items/ItemDef.hpp"
#include "logic/scripting/scripting.hpp"
diff --git a/src/logic/scripting/lua/libs/libhud.cpp b/src/logic/scripting/lua/libs/libhud.cpp
index 7f5c893c5..a457ca6ee 100644
--- a/src/logic/scripting/lua/libs/libhud.cpp
+++ b/src/logic/scripting/lua/libs/libhud.cpp
@@ -149,6 +149,15 @@ static int l_get_second_inventory(lua::State* L) {
}
}
+static int l_get_exchange_inventory(lua::State* L) {
+ auto inventory = hud->getExchangeInventory();
+ if (inventory == nullptr) {
+ return lua::pushinteger(L, 0);
+ } else {
+ return lua::pushinteger(L, inventory->getId());
+ }
+}
+
static int l_get_player(lua::State* L) {
auto player = hud->getPlayer();
return lua::pushinteger(L, player->getId());
@@ -216,6 +225,7 @@ const luaL_Reg hudlib[] = {
{"show_overlay", wrap_hud},
{"get_block_inventory", wrap_hud},
{"get_second_inventory", wrap_hud},
+ {"get_exchange_inventory", wrap_hud},
{"close", wrap_hud},
{"pause", wrap_hud},
{"resume", wrap_hud},