2024-07-06 15:18:11 -07:00

153 lines
7.6 KiB
Lua

local S = minetest.get_translator(minetest.get_current_modname())
better_commands.register_command("clear", {
params = S("[<targets>] [<items>] [<maxCount>]"),
description = S("Clears items from player inventory. Can also detect and query the amount of specified items."),
privs = { server = true },
func = function(name, param, context)
local split_param = better_commands.parse_params(param)
local selector = split_param[1]
local targets, err
if not selector then
targets = {context.executor}
else
targets, err = better_commands.parse_selector(selector, context)
if err or not targets then return false, better_commands.error(err), 0 end
end
local filter, group
if split_param[2] then
if split_param[2][5] then
split_param[3] = split_param[2][5]
end
split_param[2][5] = nil
split_param[2][6] = nil
if split_param[2][3] == "*" then
filter = "*"
elseif split_param[2][3]:sub(1,6) == "group:" then
group = true
filter = split_param[2][3]:sub(7, -1)
else
filter, err = better_commands.parse_item(split_param[2], true)
if err or not filter then return false, better_commands.error(err), 0 end
end
end
local remove_max = tonumber(split_param[3] and split_param[3][3])
if split_param[3] and not remove_max then
return false, better_commands.error(S("maxCount must be a number")), 0
end
if remove_max then
remove_max = math.floor(remove_max)
else
remove_max = -1
end
local all = not filter or filter == "*"
local last
local count = 0
local match_total = 0
for _, target in ipairs(targets) do
if target.is_player and target:is_player() then
count = count + 1
local match_count = 0
local inv = target:get_inventory()
for _, list in ipairs(better_commands.settings.clear_lists) do
local inv_list = inv:get_list(list)
if inv_list then
if all and remove_max == -1 then
inv:set_list(list, {})
elseif remove_max == 0 then
for _, stack in ipairs(inv_list) do
if all then
match_count = match_count + stack:get_count()
elseif group then
if minetest.get_item_group(stack:get_name(), filter) then
match_count = match_count + stack:get_count()
end
elseif split_param[2].extra_data then
if stack:peek_item(1):equals(filter) then
match_count = match_count + stack:get_count()
end
---@diagnostic disable-next-line: param-type-mismatch
elseif stack:get_name() == filter:get_name() then
match_count = match_count + stack:get_count()
end
end
else
for i, stack in ipairs(inv_list) do
local matches = false
if all then
matches = true
elseif group then
if minetest.get_item_group(stack:get_name(), filter) then
matches = true
end
elseif split_param[2].extra_data then
if stack:peek_item(1):equals(filter) then
matches = true
end
---@diagnostic disable-next-line: param-type-mismatch
elseif stack:get_name() == filter:get_name() then
matches = true
end
if matches then
local count = stack:get_count()
local to_remove = count
if remove_max > 0 then
to_remove = math.min(remove_max - match_count, count)
end
if to_remove == count then
inv:set_stack(list, i, ItemStack(""))
match_count = match_count + to_remove
elseif to_remove > 0 then
local result_count = count - to_remove
if result_count > 0 then
stack:set_count(result_count)
inv:set_stack(list, i, stack)
else
inv:set_stack(list, i, ItemStack(""))
end
match_count = match_count + to_remove
end
if match_count >= remove_max and remove_max > 0 then
break
end
end
end
if match_count >= remove_max and remove_max > 0 then
break
end
end
end
end
if match_count > 0 or (all and remove_max == -1) then
match_total = match_total + match_count
last = better_commands.get_entity_name(target)
end
end
end
if count < 1 then
return false, better_commands.error(S("No player was found")), 0
elseif count == 1 then
if all and remove_max == -1 then
return true, S("Removed all items from player @1", last), 1
elseif match_total < 1 then
return false, better_commands.error(S("No items were found on player @1", last)), 0
elseif remove_max == 0 then
return true, S("Found @1 matching items(s) on player @2", match_total, last), match_total
else
return true, S("Removed @1 item(s) from player @2", match_total, last), 1
end
else
if all and remove_max == -1 then
return true, S("Removed all items from @1 players", count), count
elseif match_total < 1 then
return false, better_commands.error(S("No items were found on @1 players", count)), 0
elseif remove_max == 0 then
return true, S("Found @1 matching items(s) on @2 players", match_total, count), match_total
else
return true, S("Removed @1 items from @2 players", match_total, count), count
end
end
end
})