Added /clear
This commit is contained in:
parent
429a3cb56f
commit
da3fba377a
@ -497,19 +497,22 @@ end
|
||||
---@return minetest.ItemStack? result
|
||||
---@return string? err
|
||||
---@nodiscard
|
||||
function better_commands.parse_item(item_data)
|
||||
function better_commands.parse_item(item_data, ignore_count)
|
||||
minetest.log(dump(item_data))
|
||||
if not better_commands.handle_alias(item_data[3]) then
|
||||
return nil, S("Invalid item: @1", item_data[3])
|
||||
end
|
||||
if item_data.type == "item" and not item_data.extra_data then
|
||||
local stack = ItemStack(item_data[3])
|
||||
stack:set_count(tonumber(item_data[4]) or 1)
|
||||
if not ignore_count then
|
||||
stack:set_count(tonumber(item_data[4]) or 1)
|
||||
end
|
||||
stack:set_wear(tonumber(item_data[5]) or 0)
|
||||
return stack
|
||||
elseif item_data.type == "item" then
|
||||
local arg_table = {}
|
||||
if item_data[4] then
|
||||
-- basically matching "(thing)=(thing)[,%]]"
|
||||
-- basically matching (thing)=(thing) followed by , or ]
|
||||
for key, value in item_data[4]:gmatch("([%w_]+)%s*=%s*([^,%]]+)%s*[,%]]") do
|
||||
arg_table[key:trim()] = value:trim()
|
||||
end
|
||||
@ -518,11 +521,18 @@ function better_commands.parse_item(item_data)
|
||||
if arg_table then
|
||||
local meta = stack:get_meta()
|
||||
for key, value in pairs(arg_table) do
|
||||
meta:set_string(key, value)
|
||||
minetest.log(S("@1 = @2", key, value))
|
||||
if key == "wear" then
|
||||
stack:set_wear(tonumber(value) or 0)
|
||||
else
|
||||
meta:set_string(key, value)
|
||||
end
|
||||
end
|
||||
end
|
||||
stack:set_count(tonumber(item_data[5]) or 1)
|
||||
stack:set_wear(tonumber(item_data[6]) or 1)
|
||||
if not ignore_count then
|
||||
stack:set_count(tonumber(item_data[5]) or 1)
|
||||
end
|
||||
stack:set_wear(tonumber(item_data[6]) or stack:get_wear())
|
||||
return stack
|
||||
end
|
||||
return nil, S("Invalid item: @1", item_data[3])
|
||||
|
@ -6,8 +6,4 @@ minetest.register_on_mods_loaded(function()
|
||||
return true
|
||||
end
|
||||
end)
|
||||
end)
|
||||
|
||||
function better_commands.set_spawn(player, pos)
|
||||
better_commands.spawnpoints[player:get_player_name()] = pos
|
||||
end
|
||||
end)
|
@ -1,22 +1,26 @@
|
||||
local storage = minetest.get_mod_storage()
|
||||
|
||||
function better_commands.load(key)
|
||||
local value = storage:get_string("teams")
|
||||
function better_commands.load(key, default)
|
||||
local value = storage:get_string(key)
|
||||
if value and value ~= "" then
|
||||
better_commands[key] = minetest.deserialize(value)
|
||||
better_commands[key] = minetest.deserialize(value) or default
|
||||
else
|
||||
better_commands[key] = {teams = {}, players = {}}
|
||||
better_commands[key] = default
|
||||
end
|
||||
end
|
||||
|
||||
better_commands.load("teams")
|
||||
better_commands.load("scoreboard")
|
||||
better_commands.load("spawnpoints")
|
||||
function better_commands.save(key)
|
||||
storage:set_string(key, minetest.serialize(better_commands[key]))
|
||||
end
|
||||
|
||||
better_commands.load("teams", {teams = {}})
|
||||
better_commands.load("scoreboard", {objectives = {}, players = {}, displays = {}})
|
||||
better_commands.load("spawnpoints", {})
|
||||
|
||||
better_commands.register_on_update(function ()
|
||||
storage:set_string("scoreboard", minetest.serialize(better_commands.scoreboard))
|
||||
storage:set_string("teams", minetest.serialize(better_commands.teams))
|
||||
storage:set_string("spawnpoints", minetest.serialize(better_commands.spawnpoints))
|
||||
better_commands.save("scoreboard")
|
||||
better_commands.save("teams")
|
||||
better_commands.save("spawnpoints")
|
||||
end)
|
||||
|
||||
minetest.register_on_shutdown(function()
|
||||
|
@ -19,9 +19,11 @@ Initial release. Missing *lots* of commands, several `execute` subcommands, lots
|
||||
* `placed.<itemstring>`
|
||||
* `crafted.<itemstring>`
|
||||
* Added `ascending|descending` argument for `/scoreboard objectives setdisplay`
|
||||
* Added `/gamemode` (grants/revokes `creative` priv in non-MCL games)
|
||||
* Added `/gamemode` command (grants/revokes `creative` priv in non-MCL games)
|
||||
* Added `/spawnpoint` and `/clearspawnpoint` commands
|
||||
* Added `gamemode`/`m` selector argument
|
||||
* Added `level`/`l`/`lm` selector arguments
|
||||
* Added `/clear` command
|
||||
### Bugfixes
|
||||
* The `/kill` command is more likely to successfully kill entities.
|
||||
* The `rm`/`r` selector arguments now actually treat their values as numbers (not strings), and are now inclusive as intended.
|
||||
|
@ -15,6 +15,8 @@ local command_files = {
|
||||
"setblock",
|
||||
"summon",
|
||||
"gamemode",
|
||||
"spawnpoint",
|
||||
"clear",
|
||||
}
|
||||
|
||||
for _, file in ipairs(command_files) do
|
||||
|
138
COMMANDS/clear.lua
Normal file
138
COMMANDS/clear.lua
Normal file
@ -0,0 +1,138 @@
|
||||
local S = minetest.get_translator(minetest.get_current_modname())
|
||||
|
||||
better_commands.register_command("clear", {
|
||||
description = S("Clears player inventories"),
|
||||
privs = { server = true },
|
||||
params = S("[targets] [items] [maxCount]"),
|
||||
func = function(name, param, context)
|
||||
context = better_commands.complete_context(name, context)
|
||||
if not context then return false, S("Missing context"), 0 end
|
||||
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, err, 0 end
|
||||
end
|
||||
local filter
|
||||
if split_param[2] and split_param[2][3] == "*" then
|
||||
filter = "*"
|
||||
elseif split_param[2] then
|
||||
filter, err = better_commands.parse_item(split_param[2], true)
|
||||
if err or not filter then return false, err, 0 end
|
||||
minetest.log(dump(filter:get_name()))
|
||||
end
|
||||
local remove_max = tonumber(split_param[3] and split_param[3][3])
|
||||
if split_param[3] and not remove_max then
|
||||
return false, 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
|
||||
minetest.log(dump(split_param))
|
||||
for _, target in ipairs(targets) do
|
||||
if target.is_player and target:is_player() then
|
||||
local found = false
|
||||
local match_count = 0
|
||||
local inv = target:get_inventory()
|
||||
for _, list in ipairs(better_commands.settings.clear_lists) do
|
||||
if inv:get_list(list) then
|
||||
if all and remove_max == -1 then
|
||||
inv:set_list(list, {})
|
||||
found = true
|
||||
elseif remove_max == 0 then
|
||||
for _, stack in ipairs(inv:get_list(list)) do
|
||||
if all then
|
||||
found = true
|
||||
match_count = match_count + stack:get_count()
|
||||
elseif split_param[2].extra_data then
|
||||
if stack:peek_item(1):equals(filter) then
|
||||
found = true
|
||||
match_count = match_count + stack:get_count()
|
||||
end
|
||||
---@diagnostic disable-next-line: param-type-mismatch
|
||||
elseif stack:get_name() == filter:get_name() then
|
||||
found = true
|
||||
match_count = match_count + stack:get_count()
|
||||
end
|
||||
end
|
||||
else
|
||||
for i, stack in ipairs(inv:get_list(list)) do
|
||||
local matches = false
|
||||
if all then
|
||||
matches = true
|
||||
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
|
||||
found = true
|
||||
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
|
||||
match_total = match_total + match_count
|
||||
end
|
||||
end
|
||||
if found then
|
||||
count = count + 1
|
||||
last = better_commands.get_entity_name(target)
|
||||
end
|
||||
end
|
||||
end
|
||||
if count < 1 then
|
||||
return false, S("No matching players/items")
|
||||
elseif count == 1 then
|
||||
if remove_max == 0 then
|
||||
return true, S("@1 has @2 matching items", last, match_total), match_total
|
||||
elseif all and remove_max == -1 then
|
||||
return true, S("Removed all items from @1", last), 1
|
||||
else
|
||||
return true, S("Removed @1 items from @2", match_total, last), 1
|
||||
end
|
||||
else
|
||||
if remove_max == 0 then
|
||||
return true, S("@1 matching items found in @2 players' inventories", match_total, count), match_total
|
||||
elseif all and remove_max == -1 then
|
||||
return true, S("Removed all items from @1 players", count), 1
|
||||
else
|
||||
return true, S("Removed @1 items from @2 players", match_total, count), count
|
||||
end
|
||||
end
|
||||
end
|
||||
})
|
@ -134,9 +134,9 @@ better_commands.register_command("scoreboard", {
|
||||
display = better_commands.scoreboard.displays.sidebar
|
||||
sortable = true
|
||||
else
|
||||
local color = location:match("^sidebar%.(.+)")
|
||||
local color = location:match("^sidebar%.team.(.+)")
|
||||
if not color then
|
||||
return false, S("Must be 'list', 'below_name', 'sidebar', or 'sidebar.<color>"), 0
|
||||
return false, S("Must be 'list', 'below_name', 'sidebar', or 'sidebar.team.<color>"), 0
|
||||
elseif better_commands.team_colors[color] then
|
||||
display = better_commands.scoreboard.displays.colors[color]
|
||||
better_commands.scoreboard.displays.colors[color] = {objective = objective}
|
||||
@ -172,6 +172,7 @@ better_commands.register_command("scoreboard", {
|
||||
end
|
||||
local score = tonumber(split_param[5] and split_param[5][3])
|
||||
if not score then return false, S("Missing score"), 0 end
|
||||
score = math.floor(score)
|
||||
local names, err = better_commands.get_scoreboard_names(selector, context, objective)
|
||||
if err or not names then return false, err, 0 end
|
||||
local last
|
||||
@ -416,20 +417,28 @@ better_commands.register_command("scoreboard", {
|
||||
source_scores[source] = {score = 0}
|
||||
end
|
||||
if operator == "+=" then
|
||||
target_scores[target].score = target_scores[target].score + source_scores[source].score
|
||||
target_scores[target].score = math.floor(target_scores[target].score + source_scores[source].score)
|
||||
op_string, preposition = "Added", "to"
|
||||
elseif operator == "-=" then
|
||||
target_scores[target].score = target_scores[target].score - source_scores[source].score
|
||||
target_scores[target].score = math.floor(target_scores[target].score - source_scores[source].score)
|
||||
op_string, preposition = "Subtracted", "from"
|
||||
elseif operator == "*=" then
|
||||
target_scores[target].score = target_scores[target].score * source_scores[source].score
|
||||
target_scores[target].score = math.floor(target_scores[target].score * source_scores[source].score)
|
||||
op_string, preposition, swap = "Multiplied", "by", true
|
||||
elseif operator == "/=" then
|
||||
target_scores[target].score = target_scores[target].score / source_scores[source].score
|
||||
op_string, preposition, swap = "Divided", "by", true
|
||||
if source_scores[source].score == 0 then
|
||||
minetest.chat_send_player(name, S("Skipping attempt to divide by zero"))
|
||||
else
|
||||
target_scores[target].score = math.floor(target_scores[target].score / source_scores[source].score)
|
||||
op_string, preposition, swap = "Divided", "by", true
|
||||
end
|
||||
elseif operator == "%=" then
|
||||
target_scores[target].score = target_scores[target].score % source_scores[source].score
|
||||
op_string, preposition, swap = "Modulo-ed (?)", "and", true
|
||||
if source_scores[source].score == 0 then
|
||||
minetest.chat_send_player(name, S("Skipping attempt to divide by zero"))
|
||||
else
|
||||
target_scores[target].score = math.floor(target_scores[target].score % source_scores[source].score)
|
||||
op_string, preposition, swap = "Modulo-ed (?)", "and", true
|
||||
end
|
||||
elseif operator == "=" then
|
||||
target_scores[target].score = source_scores[source].score
|
||||
op_string, preposition, swap = "Set", "to", true
|
||||
@ -605,13 +614,14 @@ better_commands.register_command("trigger", {
|
||||
else
|
||||
local value = split_param[3] and split_param[3][3]
|
||||
if not value then return false, S("Missing value"), 0 end
|
||||
if not tonumber(value) then return false, S("Value must be a number"), 0 end
|
||||
value = tonumber(value)
|
||||
if not value then return false, S("Value must be a number"), 0 end
|
||||
if subcommand == "add" then
|
||||
scores.score = scores.score + tonumber(value)
|
||||
scores.score = scores.score + math.floor(value)
|
||||
scores.enabled = false
|
||||
return true, S("Triggered [@1] (added @2 to value)", display_name, value), scores.score
|
||||
elseif subcommand == "set" then
|
||||
scores.score = tonumber(value)
|
||||
scores.score = math.floor(value)
|
||||
scores.enabled = false
|
||||
return true, S("Triggered [@1] (set value to @2)", display_name, value), scores.score
|
||||
else
|
||||
|
@ -3,7 +3,7 @@ local S = minetest.get_translator(minetest.get_current_modname())
|
||||
better_commands.register_command("spawnpoint", {
|
||||
description = S("Sets players' spawnpoints"),
|
||||
privs = {server = true},
|
||||
params = "[targets]",
|
||||
params = S("[targets]"),
|
||||
func = function (name, param, context)
|
||||
context = better_commands.complete_context(name, context)
|
||||
if not context then return false, S("Missing context"), 0 end
|
||||
@ -13,7 +13,7 @@ better_commands.register_command("spawnpoint", {
|
||||
local selector = split_param[1]
|
||||
if not selector then
|
||||
if context.executor.is_player and context.executor:is_player() then
|
||||
better_commands.spawnpoints[context.executor:get_player_name()] = context.executor:get_pos()
|
||||
better_commands.spawnpoints[context.executor:get_player_name()] = context.pos
|
||||
return true, S("Spawn point set"), 1
|
||||
else
|
||||
return false, S("Non-player entities are not supported by this command")
|
||||
@ -25,7 +25,7 @@ better_commands.register_command("spawnpoint", {
|
||||
local count = 0
|
||||
for _, target in ipairs(targets) do
|
||||
if target.is_player and target:is_player() then
|
||||
better_commands.spawnpoints[target:get_player_name()] = target:get_pos()
|
||||
better_commands.spawnpoints[target:get_player_name()] = context.pos
|
||||
count = count + 1
|
||||
last = better_commands.get_entity_name(target)
|
||||
end
|
||||
@ -33,9 +33,50 @@ better_commands.register_command("spawnpoint", {
|
||||
if count < 1 then
|
||||
return false, S("No matching players found."), 0
|
||||
elseif count == 1 then
|
||||
return true, S("Set spawn point for @1", last), 1
|
||||
return true, S("Set spawn point to @1 for @2", minetest.pos_to_string(context.pos), last), 1
|
||||
else
|
||||
return true, S("Set spawn point for @1 players", count), count
|
||||
return true, S("Set spawn point to @1 for @2 players", minetest.pos_to_string(context.pos), count), count
|
||||
end
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
better_commands.register_command("clearspawnpoint", {
|
||||
description = S("Clear players' spawnpoints"),
|
||||
privs = {server = true},
|
||||
params = "[targets]",
|
||||
func = function (name, param, context)
|
||||
context = better_commands.complete_context(name, context)
|
||||
if not context then return false, S("Missing context"), 0 end
|
||||
if not context.executor then return false, S("Missing executor"), 0 end
|
||||
local split_param, err = better_commands.parse_params(param)
|
||||
if err then return false, err, 0 end
|
||||
local selector = split_param[1]
|
||||
if not selector then
|
||||
if context.executor.is_player and context.executor:is_player() then
|
||||
better_commands.spawnpoints[context.executor:get_player_name()] = nil
|
||||
return true, S("Spawn point cleared"), 1
|
||||
else
|
||||
return false, S("Non-player entities are not supported by this command")
|
||||
end
|
||||
else
|
||||
local targets, err = better_commands.parse_selector(selector, context)
|
||||
if err or not targets then return false, err, 0 end
|
||||
local last
|
||||
local count = 0
|
||||
for _, target in ipairs(targets) do
|
||||
if target.is_player and target:is_player() then
|
||||
better_commands.spawnpoints[target:get_player_name()] = nil
|
||||
count = count + 1
|
||||
last = better_commands.get_entity_name(target)
|
||||
end
|
||||
end
|
||||
if count < 1 then
|
||||
return false, S("No matching players found."), 0
|
||||
elseif count == 1 then
|
||||
return true, S("Cleared spawn point for @2", last), 1
|
||||
else
|
||||
return true, S("Set spawn point for @2 players", count), count
|
||||
end
|
||||
end
|
||||
end
|
||||
|
8
TODO.md
8
TODO.md
@ -1,5 +1,5 @@
|
||||
# TODO
|
||||
A place for me to write out my future plans. Also, I can just copy/paste into a random generator and decide what to do next.
|
||||
A place for me to write out my future plans. I decide what to do next [randomly](https://wheelofnames.com/24r-ygp) (yes, this is genuinely how I do it).
|
||||
|
||||
- [ ] Add scoreboard playerlist and nametags (?)
|
||||
- [ ] Figure out feet/eyes since most entities don't have that
|
||||
@ -52,9 +52,9 @@ A place for me to write out my future plans. Also, I can just copy/paste into a
|
||||
- [ ] `advancement`
|
||||
- [ ] `fill` (Extra argument for LBM vs `set_node(s)`)
|
||||
- [ ] `changesetting`?
|
||||
- [ ] `clear`
|
||||
- [ ] `spawnpoint`
|
||||
- [ ] `clearspawnpoint`
|
||||
- [x] `clear`
|
||||
- [x] `spawnpoint`
|
||||
- [x] `clearspawnpoint`
|
||||
- [ ] `clone`
|
||||
- [ ] `damage`
|
||||
- [ ] `data`
|
||||
|
@ -12,6 +12,9 @@ local function get_setting(setting, default, type)
|
||||
better_commands.settings[setting] = minetest.settings:get_bool(long_setting, default)
|
||||
elseif type == "number" then
|
||||
better_commands.settings[setting] = tonumber(minetest.settings:get(long_setting)) or default
|
||||
elseif type == "comma_separated" then
|
||||
local value = minetest.settings:get(long_setting)
|
||||
better_commands.settings[setting] = value and value:split(",") or default
|
||||
end
|
||||
end
|
||||
|
||||
@ -20,6 +23,7 @@ local settings = {
|
||||
{"acovg_time", false, "bool"},
|
||||
{"save_interval", 3, "number"},
|
||||
{"kill_creative_players", false, "bool"},
|
||||
{"clear_lists", {"main", "craft", "offhand"}, "comma_separated"},
|
||||
|
||||
{"scoreboard_picked_up", true, "bool"},
|
||||
{"scoreboard_mined", true, "bool"},
|
||||
|
@ -23,4 +23,7 @@ better_commands_scoreboard_placed (Update "placed" objectives?) bool true
|
||||
better_commands_scoreboard_health (Update "health" objectives?) bool true
|
||||
|
||||
# Check player deaths for scoreboard objectives? If false, "deathCount", "teamKill", "playerKillCount", and "killedByTeam" scoreboard objectives will not update.
|
||||
better_commands_scoreboard_death (Update kill/death objectives?) bool true
|
||||
better_commands_scoreboard_death (Update kill/death objectives?) bool true
|
||||
|
||||
# Comma-separated value of lists (or *) to clear with the /clear command.
|
||||
better_commands_clear_lists (Lists to /clear) string main,craft,offhand
|
Loading…
x
Reference in New Issue
Block a user