Shift-click armor item in inventory to equip #4451

Open
opened 2024-06-21 00:18:54 +02:00 by minec · 5 comments

Feature

If you shift-click an armor item in your inventory and you don't have the corresponding armor slot filled, this should equip the armor item in the armor slot.

Why

This helps speed up inventory management and makes equipping easier. Also it's functionality that Minecraft has.

Point me to the relevant code and I can probably contribute. And if it's an engine thing I will contribute to the upstream minetest.

Thanks

<!-- Got a new feature request? Explain to us why we should consider your idea. Please follow our contributing guidelines first: https://git.minetest.land/VoxeLibre/VoxeLibre/src/branch/master/CONTRIBUTING.md#rules-about-both-bugs-and-feature-requests By submitting this issue, you agree to follow our Code of Conduct: https://git.minetest.land/VoxeLibre/VoxeLibre/src/branch/master/CODE_OF_CONDUCT.md --> ### Feature If you shift-click an armor item in your inventory and you don't have the corresponding armor slot filled, this should equip the armor item in the armor slot. ### Why This helps speed up inventory management and makes equipping easier. Also it's functionality that Minecraft has. Point me to the relevant code and I can probably contribute. And if it's an engine thing I will contribute to the upstream minetest. Thanks
minec added the
feature request
needs discussion
labels 2024-06-21 00:18:54 +02:00
Member

I believe this worked at one point and was broken by a formspec (GUI) rework. See #631 for the old issue and a link to a PR that may have broken it.

I believe this worked at one point and was broken by a formspec (GUI) rework. See https://git.minetest.land/VoxeLibre/VoxeLibre/issues/631 for the old issue and a link to a PR that may have broken it.

This works in Mineclonia and I'm missing it in VoxeLibre, too. IMHO this should be implemented (again), as it is very useful.

This works in Mineclonia and I'm missing it in VoxeLibre, too. IMHO this should be implemented (again), as it is very useful.
ancientmarinerdev added the
gameplay
#P4 priority: medium
labels 2024-06-21 02:48:19 +02:00
Author

I spent the last few hours digging through the source code. I had to look at the minetest source (src/gui/guiFormSpecMenu.cpp), which led me to the listrings.

This change will equip armor when shift-clicked... but it messes up shift-click for non-armor items:

diff --git a/mods/HUD/mcl_inventory/survival.lua b/mods/HUD/mcl_inventory/survival.lua
index 253109cb7..864219b83 100644
--- a/mods/HUD/mcl_inventory/survival.lua
+++ b/mods/HUD/mcl_inventory/survival.lua
@@ -136,10 +136,10 @@ local main_page_static = table.concat({
 
        --Listring
        "listring[current_player;main]",
-       "listring[current_player;craft]",
-       "listring[current_player;main]",
        "listring[current_player;armor]",
        "listring[current_player;main]",
+       "listring[current_player;craft]",
+       "listring[current_player;main]",
 })
 
 mcl_inventory.register_survival_inventory_tab({
I spent the last few hours digging through the source code. I had to look at the minetest source (`src/gui/guiFormSpecMenu.cpp`), which led me to the listrings. This change will equip armor when shift-clicked... but it messes up shift-click for non-armor items: ```diff diff --git a/mods/HUD/mcl_inventory/survival.lua b/mods/HUD/mcl_inventory/survival.lua index 253109cb7..864219b83 100644 --- a/mods/HUD/mcl_inventory/survival.lua +++ b/mods/HUD/mcl_inventory/survival.lua @@ -136,10 +136,10 @@ local main_page_static = table.concat({ --Listring "listring[current_player;main]", - "listring[current_player;craft]", - "listring[current_player;main]", "listring[current_player;armor]", "listring[current_player;main]", + "listring[current_player;craft]", + "listring[current_player;main]", }) mcl_inventory.register_survival_inventory_tab({ ```
Member

Thanks for looking into this.

I'll recommend doing what Mineclonia did with furnaces and possibly others: add a hidden sorter inventory, list it after the main inventory list and use a callback to move the items to the correct locations. I'm not sure there is really another way to have shift-click into the armor slots and the crafting grid without this.

For a player inventory, I think you will need to use minetest.register_on_player_inventory_action(function(player, action, inventory, inventory_info)) to process the sorter inventory.

Thanks for looking into this. I'll recommend doing [what Mineclonia did with furnaces](https://codeberg.org/mineclonia/mineclonia/commit/e6ca5b421fe3d3b5129484a3712d41f42fbb95b1) and possibly others: add a hidden sorter inventory, list it after the main inventory list and use a callback to move the items to the correct locations. I'm not sure there is really another way to have shift-click into the armor slots and the crafting grid without this. For a player inventory, I think you will need to use `minetest.register_on_player_inventory_action(function(player, action, inventory, inventory_info))` to process the sorter inventory.
Author
Click to expand
diff --git a/mods/HUD/mcl_inventory/survival.lua b/mods/HUD/mcl_inventory/survival.lua
index 253109cb7..d8bd0d331 100644
--- a/mods/HUD/mcl_inventory/survival.lua
+++ b/mods/HUD/mcl_inventory/survival.lua
@@ -42,14 +42,75 @@ function get_player_tab(player)
 	return tab
 end
 
+---@param player mt.PlayerObjectRef
+local function init(player)
+	local playername = player:get_player_name()
+	local sorter = minetest.create_detached_inventory("sorter", {
+		allow_put = function(inv, listname, index, stack, player)
+			minetest.chat_send_player(player:get_player_name(), "Allow YAY")
+			return stack:get_count()
+		end,
+		on_put = function(inv, listname, index, stack, player)
+			local pinv = player:get_inventory()
+
+			local rest
+			local is_armor = false
+			local item_name = stack:get_name()
+			local item_def = minetest.registered_items[item_name]
+			if item_def and item_def.groups and item_def.groups.armor then
+				is_armor = true
+			end
+			if is_armor then
+				rest = pinv:add_item("armor", stack)
+				inv:remove_item("sorter", stack)
+				minetest.chat_send_player(player:get_player_name(), "YAY")
+			else
+				minetest.chat_send_player(player:get_player_name(), "failed")
+				rest = stack
+			end
+			if rest and rest:get_count() > 0 then
+				pinv:add_item("main", rest)
+			end
+			inv:set_stack("sorter", 1, nil)
+		end,
+		allow_move = function(inv, listname, index, stack, player)
+			minetest.chat_send_player(player:get_player_name(), "allow move")
+			return stack:get_count()
+		end,
+		on_move = function(inv, listname, index, stack, player)
+			minetest.chat_send_player(player:get_player_name(), "onmove")
+		end,
+	}, playername)
+	sorter:set_size("main", 1)
+end
+
 minetest.register_on_joinplayer(function(player, last_login)
 	get_player_tab(player)
+	init(player)
 end)
 
 minetest.register_on_leaveplayer(function(player, timed_out)
 	player_current_tab[player] = nil
 end)
 
+minetest.register_on_player_inventory_action(function(player, action, inventory, inventory_info)
+	if action == "take" or action == "put" then
+		minetest.chat_send_player(player:get_player_name(), action .. " " .. inventory_info.listname)
+	end
+	if action == "take" and inventory_info.listname == "sorter" then
+		minetest.chat_send_player(player:get_player_name(), "Moving to sorter!")
+		local stack = inventory:get_stack(inventory_info.to_list, inventory_info.to_index)
+		-- Check if the item is armor
+		local item_def = minetest.registered_items[stack:get_name()]
+		if item_def and item_def.groups and item_def.groups.armor then
+			inventory:add_item("armor", stack)
+		else
+			inventory:add_item("main", stack)
+		end
+		inventory:remove_item("sorter", stack)
+	end
+end)
+
 ---@param player ObjectRef
 ---@param content string
 ---@param inventory boolean
@@ -136,6 +197,8 @@ local main_page_static = table.concat({
 
 	--Listring
 	"listring[current_player;main]",
+	"listring[detached:sorter;main]",
+	"listring[current_player;main]",
 	"listring[current_player;craft]",
 	"listring[current_player;main]",
 	"listring[current_player;armor]",

Unfortunately my crack at it wasn't successful. It seems to work for one item (which if armor gets put in the helmet slot) and then no longer accepts anything. I assume it's because something gets "stuck" in the slot and I'm not taking care of it or something.

<details> <summary>Click to expand</summary> ```diff diff --git a/mods/HUD/mcl_inventory/survival.lua b/mods/HUD/mcl_inventory/survival.lua index 253109cb7..d8bd0d331 100644 --- a/mods/HUD/mcl_inventory/survival.lua +++ b/mods/HUD/mcl_inventory/survival.lua @@ -42,14 +42,75 @@ function get_player_tab(player) return tab end +---@param player mt.PlayerObjectRef +local function init(player) + local playername = player:get_player_name() + local sorter = minetest.create_detached_inventory("sorter", { + allow_put = function(inv, listname, index, stack, player) + minetest.chat_send_player(player:get_player_name(), "Allow YAY") + return stack:get_count() + end, + on_put = function(inv, listname, index, stack, player) + local pinv = player:get_inventory() + + local rest + local is_armor = false + local item_name = stack:get_name() + local item_def = minetest.registered_items[item_name] + if item_def and item_def.groups and item_def.groups.armor then + is_armor = true + end + if is_armor then + rest = pinv:add_item("armor", stack) + inv:remove_item("sorter", stack) + minetest.chat_send_player(player:get_player_name(), "YAY") + else + minetest.chat_send_player(player:get_player_name(), "failed") + rest = stack + end + if rest and rest:get_count() > 0 then + pinv:add_item("main", rest) + end + inv:set_stack("sorter", 1, nil) + end, + allow_move = function(inv, listname, index, stack, player) + minetest.chat_send_player(player:get_player_name(), "allow move") + return stack:get_count() + end, + on_move = function(inv, listname, index, stack, player) + minetest.chat_send_player(player:get_player_name(), "onmove") + end, + }, playername) + sorter:set_size("main", 1) +end + minetest.register_on_joinplayer(function(player, last_login) get_player_tab(player) + init(player) end) minetest.register_on_leaveplayer(function(player, timed_out) player_current_tab[player] = nil end) +minetest.register_on_player_inventory_action(function(player, action, inventory, inventory_info) + if action == "take" or action == "put" then + minetest.chat_send_player(player:get_player_name(), action .. " " .. inventory_info.listname) + end + if action == "take" and inventory_info.listname == "sorter" then + minetest.chat_send_player(player:get_player_name(), "Moving to sorter!") + local stack = inventory:get_stack(inventory_info.to_list, inventory_info.to_index) + -- Check if the item is armor + local item_def = minetest.registered_items[stack:get_name()] + if item_def and item_def.groups and item_def.groups.armor then + inventory:add_item("armor", stack) + else + inventory:add_item("main", stack) + end + inventory:remove_item("sorter", stack) + end +end) + ---@param player ObjectRef ---@param content string ---@param inventory boolean @@ -136,6 +197,8 @@ local main_page_static = table.concat({ --Listring "listring[current_player;main]", + "listring[detached:sorter;main]", + "listring[current_player;main]", "listring[current_player;craft]", "listring[current_player;main]", "listring[current_player;armor]", ``` </details> Unfortunately my crack at it wasn't successful. It seems to work for one item (which if armor gets put in the helmet slot) and then no longer accepts anything. I assume it's because something gets "stuck" in the slot and I'm not taking care of it or something.
Sign in to join this conversation.
No Milestone
No project
No Assignees
3 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: VoxeLibre/VoxeLibre#4451
No description provided.