e77473e800
Group levels are now specified as a list of names when registering a digging group. Digging groups which do not have specified levels will support tools having two levels, 0 and 1 where 0 means the tool can dig but not harvest the node and 1 means it can also harvest the node. If more levels are required one has to specifiy them when registering the digging group.
321 lines
10 KiB
Lua
321 lines
10 KiB
Lua
--[[
|
|
This mod implements a HACK to make 100% sure the digging times of all tools
|
|
match Minecraft's perfectly. The digging times system of Minetest is very
|
|
different, so this weird group trickery has to be used. In Minecraft, each
|
|
block has a hardness and the actual Minecraft digging time is determined by
|
|
this:
|
|
|
|
1) The block's hardness
|
|
2) The tool being used (the tool_multiplier and its efficiency level)
|
|
3) Whether the tool is considered as "eligible" for the block
|
|
(e.g. only diamond pick eligible for obsidian)
|
|
|
|
See Minecraft Wiki <http://minecraft.gamepedia.com/Minecraft_Wiki> for more
|
|
information.
|
|
|
|
How the mod is used
|
|
===================
|
|
|
|
In MineClone 2, all diggable node have the hardness set in the custom field
|
|
"_mcl_hardness" (0 by default). Digging groups are registered using the
|
|
following code:
|
|
|
|
mcl_autogroup.register_diggroup("pickaxey", {
|
|
levels = { "wood", "gold", "stone", "iron", "diamond" }
|
|
})
|
|
mcl_autogroup.register_diggroup("shovely")
|
|
mcl_autogroup.register_diggroup("shovely")
|
|
|
|
The first line registers "pickaxey" as a digging group. The "levels" field
|
|
indicates that the digging group have 5 levels (in this case one for each
|
|
material of a pickaxe). The second line registers "shovely" as a digging group
|
|
which does not have separate levels (if the "levels" field is not set it
|
|
defaults to 0).
|
|
|
|
Nodes indicate that they belong to a particular digging group by being member of
|
|
the digging group in their node definition. "mcl_core:dirt" for example has
|
|
shovely=1 in its groups. If the digging group has multiple levels the value of
|
|
the group indicates which digging level the node requires.
|
|
"mcl_core:stone_with_gold" for example has pickaxey=4 because it requires a
|
|
pickaxe of level 4 ("stone") to be mined.
|
|
|
|
For tools to be able to dig nodes of the digging groups they need to use the
|
|
have the custom field "_mcl_autogroup_groupcaps" function to get the groupcaps.
|
|
See "mcl_tools/init.lua" for examples of this.
|
|
|
|
Information about the mod
|
|
=========================
|
|
|
|
The mod is split up into two parts, mcl_autogroup and _mcl_autogroup.
|
|
mcl_autogroup contains the API functions used to register custom digging groups.
|
|
_mcl_autogroup contains most of the code. The leading underscore in the name
|
|
"_mcl_autogroup" is used to force Minetest to load that part of the mod as late
|
|
as possible. Minetest loads mods in reverse alphabetical order.
|
|
|
|
This also means that it is very important that no mod adds _mcl_autogroups as a
|
|
dependency.
|
|
--]]
|
|
|
|
-- Returns a table containing the unique "_mcl_hardness" for nodes belonging to
|
|
-- each diggroup.
|
|
local function get_hardness_values_for_groups()
|
|
local maps = {}
|
|
local values = {}
|
|
for g, _ in pairs(mcl_autogroup.registered_diggroups) do
|
|
maps[g] = {}
|
|
values[g] = {}
|
|
end
|
|
|
|
for _, ndef in pairs(minetest.registered_nodes) do
|
|
for g, _ in pairs(mcl_autogroup.registered_diggroups) do
|
|
if ndef.groups[g] ~= nil then
|
|
maps[g][ndef._mcl_hardness or 0] = true
|
|
end
|
|
end
|
|
end
|
|
|
|
for g, map in pairs(maps) do
|
|
for k, _ in pairs(map) do
|
|
table.insert(values[g], k)
|
|
end
|
|
end
|
|
|
|
for g, _ in pairs(mcl_autogroup.registered_diggroups) do
|
|
table.sort(values[g])
|
|
end
|
|
return values
|
|
end
|
|
|
|
-- Returns a table containing a table indexed by "_mcl_hardness_value" to get
|
|
-- its index in the list of unique hardnesses for each diggroup.
|
|
local function get_hardness_lookup_for_groups(hardness_values)
|
|
map = {}
|
|
for g, values in pairs(hardness_values) do
|
|
map[g] = {}
|
|
for k, v in pairs(values) do
|
|
map[g][v] = k
|
|
end
|
|
end
|
|
return map
|
|
end
|
|
|
|
-- Array of unique hardness values for each group which affects dig time.
|
|
local hardness_values = get_hardness_values_for_groups()
|
|
|
|
-- Map indexed by hardness values which return the index of that value in
|
|
-- hardness_value. Used for quick lookup.
|
|
local hardness_lookup = get_hardness_lookup_for_groups(hardness_values)
|
|
|
|
local function compute_creativetimes(group)
|
|
local creativetimes = {}
|
|
|
|
for index, hardness in pairs(hardness_values[group]) do
|
|
table.insert(creativetimes, 0)
|
|
end
|
|
|
|
return creativetimes
|
|
end
|
|
|
|
-- Get the list of digging times for using a specific tool on a specific
|
|
-- diggroup.
|
|
--
|
|
-- Parameters:
|
|
-- group - the group which it is digging
|
|
-- can_harvest - if the tool can harvest the block
|
|
-- tool_multiplier - dig speed multiplier for tool (default 1)
|
|
-- efficiency - efficiency level for the tool (default 0)
|
|
local function get_digtimes(group, can_harvest, tool_multiplier, efficiency)
|
|
efficiency = efficiency or 0
|
|
tool_multiplier = tool_multiplier or 1
|
|
speed_multiplier = tool_multiplier
|
|
if efficiency then
|
|
speed_multiplier = speed_multiplier + efficiency * efficiency + 1
|
|
end
|
|
|
|
local digtimes = {}
|
|
|
|
for index, hardness in pairs(hardness_values[group]) do
|
|
local digtime = (hardness or 0) / speed_multiplier
|
|
if can_harvest then
|
|
digtime = digtime * 1.5
|
|
else
|
|
digtime = digtime * 5
|
|
end
|
|
|
|
if digtime <= 0.05 then
|
|
digtime = 0
|
|
else
|
|
digtime = math.ceil(digtime * 20) / 20
|
|
end
|
|
table.insert(digtimes, digtime)
|
|
end
|
|
|
|
return digtimes
|
|
end
|
|
|
|
-- Get one groupcap field for using a specific tool on a specific group.
|
|
local function get_groupcap(group, can_harvest, multiplier, efficiency, uses)
|
|
return {
|
|
times = get_digtimes(group, can_harvest, multiplier, efficiency),
|
|
uses = uses,
|
|
maxlevel = 0,
|
|
}
|
|
end
|
|
|
|
local function add_groupcaps(groupcaps, groupcaps_def, efficiency)
|
|
for g, capsdef in pairs(groupcaps_def) do
|
|
local mult = capsdef.tool_multiplier or 1
|
|
local uses = capsdef.uses
|
|
local def = mcl_autogroup.registered_diggroups[g]
|
|
local max_level = def.levels and #def.levels or 1
|
|
local level = math.min(capsdef.level or max_level, max_level)
|
|
|
|
if def.levels then
|
|
groupcaps[g .. "_dig_default"] = get_groupcap(g, false, mult, efficiency, uses)
|
|
if level > 0 then
|
|
groupcaps[g .. "_dig_" .. def.levels[level]] = get_groupcap(g, true, mult, efficiency, uses)
|
|
end
|
|
else
|
|
groupcaps[g .. "_dig"] = get_groupcap(g, level > 0, mult, efficiency, uses)
|
|
end
|
|
end
|
|
return groupcaps
|
|
end
|
|
|
|
-- Checks if the given node would drop its useful drop if dug by a given tool.
|
|
-- Returns true if it will yield its useful drop, false otherwise.
|
|
function mcl_autogroup.can_harvest(nodename, toolname)
|
|
local ndef = minetest.registered_nodes[nodename]
|
|
|
|
if minetest.get_item_group(nodename, "dig_immediate") >= 2 then
|
|
return true
|
|
end
|
|
|
|
-- Check if it can be dug by tool
|
|
local tdef = minetest.registered_tools[toolname]
|
|
if tdef then
|
|
for g, gdef in pairs(tdef._mcl_autogroup_groupcaps) do
|
|
if ndef.groups[g] then
|
|
if not gdef.level or ndef.groups[g] <= gdef.level then
|
|
return true
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Check if it can be dug by hand
|
|
local tdef = minetest.registered_tools[""]
|
|
if tdef then
|
|
for g, gdef in pairs(tdef._mcl_autogroup_groupcaps) do
|
|
if ndef.groups[g] then
|
|
if not gdef.level or ndef.groups[g] <= gdef.level then
|
|
return true
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
return false
|
|
end
|
|
|
|
-- Get one groupcap field for using a specific tool on a specific group.
|
|
local function get_groupcap(group, can_harvest, multiplier, efficiency, uses)
|
|
return {
|
|
times = get_digtimes(group, can_harvest, multiplier, efficiency),
|
|
uses = uses,
|
|
maxlevel = 0,
|
|
}
|
|
end
|
|
|
|
-- Get the groupcaps for a tool. This function returns "groupcaps" table of
|
|
-- digging which should be put in the "tool_capabilities" of the tool definition
|
|
-- or in the metadata of an enchanted tool.
|
|
--
|
|
-- Parameters:
|
|
-- toolname - Name of the tool being enchanted (like "mcl_tools:diamond_pickaxe")
|
|
-- efficiency - The efficiency level the tool is enchanted with (default 0)
|
|
--
|
|
-- NOTE:
|
|
-- This function can only be called after mod initialization. Otherwise a mod
|
|
-- would have to add _mcl_autogroup as a dependency which would break the mod
|
|
-- loading order.
|
|
function mcl_autogroup.get_groupcaps(toolname, efficiency)
|
|
local tdef = minetest.registered_tools[toolname]
|
|
local groupcaps = table.copy(tdef.tool_capabilities.groupcaps or {})
|
|
add_groupcaps(groupcaps, tdef._mcl_autogroup_groupcaps, efficiency)
|
|
return groupcaps
|
|
end
|
|
|
|
-- Get the wear from using a tool on a digging group.
|
|
--
|
|
-- Parameters
|
|
-- toolname - Name of the tool used
|
|
-- diggroup - The name of the diggroup the tool is used on
|
|
--
|
|
-- NOTE:
|
|
-- This function can only be called after mod initialization. Otherwise a mod
|
|
-- would have to add _mcl_autogroup as a dependency which would break the mod
|
|
-- loading order.
|
|
function mcl_autogroup.get_wear(toolname, diggroup)
|
|
local tdef = minetest.registered_tools[toolname]
|
|
local uses = tdef._mcl_autogroup_groupcaps[diggroup].uses
|
|
return math.ceil(65535 / uses)
|
|
end
|
|
|
|
local overwrite = function()
|
|
for nname, ndef in pairs(minetest.registered_nodes) do
|
|
local newgroups = table.copy(ndef.groups)
|
|
if (nname ~= "ignore" and ndef.diggable) then
|
|
-- Automatically assign the "solid" group for solid nodes
|
|
if (ndef.walkable == nil or ndef.walkable == true)
|
|
and (ndef.collision_box == nil or ndef.collision_box.type == "regular")
|
|
and (ndef.node_box == nil or ndef.node_box.type == "regular")
|
|
and (ndef.groups.not_solid == 0 or ndef.groups.not_solid == nil) then
|
|
newgroups.solid = 1
|
|
end
|
|
-- Automatically assign the "opaque" group for opaque nodes
|
|
if (not (ndef.paramtype == "light" or ndef.sunlight_propagates)) and
|
|
(ndef.groups.not_opaque == 0 or ndef.groups.not_opaque == nil) then
|
|
newgroups.opaque = 1
|
|
end
|
|
|
|
-- Assign groups used for digging this node depending on
|
|
-- the registered digging groups
|
|
for g, gdef in pairs(mcl_autogroup.registered_diggroups) do
|
|
local index = hardness_lookup[g][ndef._mcl_hardness or 0]
|
|
if ndef.groups[g] then
|
|
if gdef.levels then
|
|
newgroups[g .. "_dig_default"] = index
|
|
|
|
for i = ndef.groups[g], #gdef.levels do
|
|
newgroups[g .. "_dig_" .. gdef.levels[i]] = index
|
|
end
|
|
else
|
|
newgroups[g .. "_dig"] = index
|
|
end
|
|
end
|
|
end
|
|
|
|
minetest.override_item(nname, {
|
|
groups = newgroups
|
|
})
|
|
end
|
|
end
|
|
|
|
for tname, tdef in pairs(minetest.registered_tools) do
|
|
-- Assign groupcaps for digging the registered digging groups
|
|
-- depending on the _mcl_autogroup_groupcaps in the tool
|
|
-- definition
|
|
if tdef._mcl_autogroup_groupcaps then
|
|
local toolcaps = table.copy(tdef.tool_capabilities) or {}
|
|
toolcaps.groupcaps = mcl_autogroup.get_groupcaps(tname)
|
|
|
|
minetest.override_item(tname, {
|
|
tool_capabilities = toolcaps
|
|
})
|
|
end
|
|
end
|
|
end
|
|
|
|
overwrite()
|