mods that hopefully work for a TechAge-based pack
This commit is contained in:
@@ -0,0 +1,282 @@
|
||||
-- eye_spy/tools.lua
|
||||
-- Tool detection and dig-hint helpers.
|
||||
-- Extracted from functions.lua. Runs after functions.lua, so eye_spy.S and
|
||||
-- eye_spy.cg are already available when this file is executed.
|
||||
|
||||
local S = eye_spy.S
|
||||
|
||||
------------------------------------------------------------
|
||||
-- Group → tool-type mappings for Minetest Game
|
||||
------------------------------------------------------------
|
||||
|
||||
-- Maps dig group names to human-readable tool-type labels (MTG).
|
||||
local GROUP_TO_TOOL_MTG = {
|
||||
cracky = S("Pickaxe"),
|
||||
crumbly = S("Shovel"),
|
||||
choppy = S("Axe"),
|
||||
snappy = S("Sword"),
|
||||
dig_immediate = S("Hand"),
|
||||
}
|
||||
|
||||
-- Priority order for MTG group lookup (most-specific first).
|
||||
local GROUP_ORDER_MTG = { "dig_immediate", "snappy", "crumbly", "choppy", "cracky" }
|
||||
|
||||
------------------------------------------------------------
|
||||
-- Group → tool-type mappings for MineClone / VoxeLibre
|
||||
------------------------------------------------------------
|
||||
|
||||
-- Maps dig group names to human-readable tool-type labels (MCL).
|
||||
local GROUP_TO_TOOL_MC = {
|
||||
swordy = S("Sword"),
|
||||
handy = S("Hand"),
|
||||
pickaxey = S("Pickaxe"),
|
||||
shovely = S("Shovel"),
|
||||
axey = S("Axe"),
|
||||
shearsy = S("Shears"),
|
||||
dig_immediate = S("Hand"),
|
||||
}
|
||||
|
||||
-- Priority order for MCL group lookup (most-specific first).
|
||||
local GROUP_ORDER_MC = { "dig_immediate", "handy", "swordy", "shearsy", "shovely", "axey", "pickaxey" }
|
||||
|
||||
------------------------------------------------------------
|
||||
-- Internal helpers
|
||||
------------------------------------------------------------
|
||||
|
||||
-- Returns a shallow copy of an ipairs-iterable list.
|
||||
local function clone_list(values)
|
||||
local result = {}
|
||||
|
||||
for index, value in ipairs(values or {}) do
|
||||
result[index] = value
|
||||
end
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
-- Appends `value` to `list` only when it is not already present.
|
||||
-- Ignores nil and empty-string values.
|
||||
local function append_unique(list, value)
|
||||
if not value or value == "" then
|
||||
return
|
||||
end
|
||||
|
||||
for _, existing in ipairs(list) do
|
||||
if existing == value then
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
list[#list + 1] = value
|
||||
end
|
||||
|
||||
-- Returns the group→tool map and ordered group list appropriate for the
|
||||
-- currently-running game. Uses eye_spy.cg (set by init.lua).
|
||||
local function get_tool_mapping(game_id)
|
||||
if game_id == "mineclone" then
|
||||
return GROUP_TO_TOOL_MC, GROUP_ORDER_MC
|
||||
end
|
||||
|
||||
return GROUP_TO_TOOL_MTG, GROUP_ORDER_MTG
|
||||
end
|
||||
|
||||
-- Collects every tool-type label that applies to `node_groups`, in priority
|
||||
-- order, de-duplicated.
|
||||
local function collect_tool_types(node_groups, group_to_tool, group_order)
|
||||
local result = {}
|
||||
|
||||
for _, group in ipairs(group_order) do
|
||||
if node_groups[group] and group_to_tool[group] then
|
||||
append_unique(result, group_to_tool[group])
|
||||
end
|
||||
end
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
-- Returns the single highest-priority dig group and its tool-type label for
|
||||
-- `node_groups`. Returns nil, S("None") when no matching group is found.
|
||||
local function get_preferred_tool_group(node_groups, group_to_tool, group_order)
|
||||
for _, group in ipairs(group_order) do
|
||||
if node_groups[group] and group_to_tool[group] then
|
||||
return group, group_to_tool[group]
|
||||
end
|
||||
end
|
||||
|
||||
return nil, S("None")
|
||||
end
|
||||
|
||||
-- Builds a display string from the full set of required tool types and the
|
||||
-- single best/preferred tool type.
|
||||
--
|
||||
-- Examples:
|
||||
-- { "Pickaxe" }, "Pickaxe" → "Pickaxe"
|
||||
-- { "Axe", "Pickaxe" }, "Pickaxe" → "Axe / Pickaxe | Pickaxe"
|
||||
local function format_tool_summary(minimum_types, best_type)
|
||||
local minimum_label = table.concat(minimum_types or {}, " / ")
|
||||
|
||||
if best_type and best_type ~= "" and best_type ~= S("None") and best_type ~= S("Unknown") then
|
||||
if minimum_label == "" then
|
||||
return best_type
|
||||
end
|
||||
|
||||
-- Single entry that matches best_type exactly — no need to repeat it.
|
||||
if #minimum_types == 1 and minimum_types[1] == best_type then
|
||||
return best_type
|
||||
end
|
||||
|
||||
-- If best_type is already listed in minimum_types, just show the list.
|
||||
for _, minimum_type in ipairs(minimum_types or {}) do
|
||||
if minimum_type == best_type then
|
||||
return minimum_label
|
||||
end
|
||||
end
|
||||
|
||||
-- best_type is not in the minimum list — append it after a separator.
|
||||
return minimum_label .. " | " .. best_type
|
||||
end
|
||||
|
||||
if minimum_label ~= "" then
|
||||
return minimum_label
|
||||
end
|
||||
|
||||
return S("Unknown")
|
||||
end
|
||||
|
||||
-- Returns true when `itemdef` has groupcaps for `preferred_group`.
|
||||
-- dig_immediate is never considered a "match" because any item can break those
|
||||
-- nodes instantly.
|
||||
local function tool_matches_group(itemdef, preferred_group)
|
||||
if not preferred_group or preferred_group == "dig_immediate" then
|
||||
return false
|
||||
end
|
||||
|
||||
local caps = itemdef and itemdef.tool_capabilities
|
||||
local groupcaps = caps and caps.groupcaps
|
||||
|
||||
return groupcaps and groupcaps[preferred_group] ~= nil or false
|
||||
end
|
||||
|
||||
------------------------------------------------------------
|
||||
-- Public API
|
||||
------------------------------------------------------------
|
||||
|
||||
-- Returns whether `toolstack` can dig `nodename`, plus the dig time.
|
||||
-- Returns false, nil when `toolstack` is nil or the node is unknown.
|
||||
function eye_spy.tool_can_dig_node(toolstack, nodename)
|
||||
-- Nil-guard: no stack means no digging ability.
|
||||
if not toolstack then
|
||||
return false, nil
|
||||
end
|
||||
|
||||
local ndef = minetest.registered_nodes[nodename]
|
||||
|
||||
if not ndef then
|
||||
return false, nil
|
||||
end
|
||||
|
||||
local tool_caps = toolstack:get_tool_capabilities()
|
||||
local node_groups = ndef.groups or {}
|
||||
local dig_params = minetest.get_dig_params(node_groups, tool_caps)
|
||||
|
||||
return dig_params.diggable, dig_params.time
|
||||
end
|
||||
|
||||
-- Returns a filtered copy of `source` that omits every entry whose `.name`
|
||||
-- field contains any substring listed in `blocked`.
|
||||
function eye_spy.filter_out_by_name(source, blocked)
|
||||
local result = {}
|
||||
|
||||
for _, entry in ipairs(source) do
|
||||
local name = entry.name or ""
|
||||
local keep = true
|
||||
|
||||
for _, word in ipairs(blocked) do
|
||||
if string.find(name, word, 1, true) then
|
||||
keep = false
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if keep then
|
||||
table.insert(result, entry)
|
||||
end
|
||||
end
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
-- Returns the highest `maxlevel` value found across all groupcaps of
|
||||
-- `itemdef`. Returns 0 when `itemdef` has no tool_capabilities.
|
||||
function eye_spy.get_tool_maxlevel(itemdef)
|
||||
local maxlevel = 0
|
||||
|
||||
if not itemdef.tool_capabilities then
|
||||
return 0
|
||||
end
|
||||
|
||||
for _, gc in pairs(itemdef.tool_capabilities.groupcaps or {}) do
|
||||
if gc.maxlevel and gc.maxlevel > maxlevel then
|
||||
maxlevel = gc.maxlevel
|
||||
end
|
||||
end
|
||||
|
||||
return maxlevel
|
||||
end
|
||||
|
||||
-- Returns a human-readable tool-hint string for `node_name` (or nil when no
|
||||
-- hint is applicable) and a boolean indicating whether the currently wielded
|
||||
-- `toolstack` is an appropriate tool for digging that node.
|
||||
function eye_spy.get_node_tool_hint_and_match(node_name, toolstack)
|
||||
if not node_name or node_name == "" then
|
||||
return nil, false
|
||||
end
|
||||
|
||||
local def = minetest.registered_nodes[node_name]
|
||||
|
||||
if not def or not def.groups then
|
||||
return nil, false
|
||||
end
|
||||
|
||||
local node_groups = def.groups
|
||||
local group_to_tool, group_order = get_tool_mapping(eye_spy.cg)
|
||||
local minimum_types = collect_tool_types(node_groups, group_to_tool, group_order)
|
||||
local preferred_group, tooltype = get_preferred_tool_group(node_groups, group_to_tool, group_order)
|
||||
local summary = format_tool_summary(minimum_types, tooltype)
|
||||
|
||||
-- Suppress generic/unhelpful labels.
|
||||
if summary == S("Unknown") or summary == S("None") then
|
||||
summary = nil
|
||||
end
|
||||
|
||||
-- Nodes with no preferred dig group (or dig_immediate) are considered
|
||||
-- compatible with any held item for colour-state purposes.
|
||||
if not preferred_group or preferred_group == "dig_immediate" then
|
||||
return summary, true
|
||||
end
|
||||
|
||||
local itemdef = toolstack and toolstack.get_definition and toolstack:get_definition() or nil
|
||||
local caps = itemdef and itemdef.tool_capabilities or nil
|
||||
local groupcaps = caps and caps.groupcaps or nil
|
||||
local matches = groupcaps and groupcaps[preferred_group] ~= nil or false
|
||||
|
||||
return summary, matches
|
||||
end
|
||||
|
||||
-- Returns the effective reach range for `player` based on the wielded item
|
||||
-- definition, falling back to creative-mode range (10) or default range (4).
|
||||
function eye_spy.get_player_range(player)
|
||||
local wield = player:get_wielded_item()
|
||||
local def = wield:get_definition()
|
||||
|
||||
-- Nil-guard: definition may be absent for unknown item types.
|
||||
if def and def.range then
|
||||
return def.range
|
||||
end
|
||||
|
||||
if minetest.is_creative_enabled(player:get_player_name()) then
|
||||
return 10
|
||||
end
|
||||
|
||||
return 4
|
||||
end
|
||||
Reference in New Issue
Block a user