5b0459e4bb
Many processes that have a significant speed/time component can now have speeds adjusted (as a multiplier from base rate) via settings. Things that can be adjusted: - Tool speeds (including digging and pummeling) - Cooking and pummel recipe durations - Soaking processes like tree growth, peat fermentation The settings are hierarchical, so groups of rates can be adjusted together, and a further multiplier can be applied to each member of the group. The settings are calculated dynamically, for power users only, and documenting them is out of scope for the project. Specifically, this should help tuning for Kimapr's SkyBlock, and possibly other mods involving signficant gameplay rebalancing.
180 lines
5.3 KiB
Lua
180 lines
5.3 KiB
Lua
-- LUALOCALS < ---------------------------------------------------------
|
|
local ItemStack, ipairs, minetest, nodecore, pairs, type
|
|
= ItemStack, ipairs, minetest, nodecore, pairs, type
|
|
-- LUALOCALS > ---------------------------------------------------------
|
|
|
|
local function addgroups(sum, pos)
|
|
local node = minetest.get_node(pos)
|
|
local def = minetest.registered_items[node.name] or {}
|
|
if not def.groups then return end
|
|
for k, v in pairs(def.groups) do
|
|
sum[k] = (sum[k] or 0) + v
|
|
end
|
|
end
|
|
|
|
local function craftcheck(recipe, pos, node, data, xx, xz, zx, zz)
|
|
local function rel(x, y, z)
|
|
return {
|
|
x = pos.x + xx * x + zx * z,
|
|
y = pos.y + y,
|
|
z = pos.z + xz * x + zz * z
|
|
}
|
|
end
|
|
data.rel = rel
|
|
data.wield = ItemStack(data.wield or data.crafter and data.crafter:get_wielded_item())
|
|
if recipe.check and not recipe.check(pos, data) then return end
|
|
if recipe.wield and (not data.wield or not nodecore.match(
|
|
{stack = data.wield}, recipe.wield)) then return end
|
|
if recipe.normal then
|
|
if data.pointed.type ~= "node" or
|
|
recipe.normal.y ~= data.pointed.above.y - data.pointed.under.y then return end
|
|
local rx = recipe.normal.x * xx + recipe.normal.z * zx
|
|
if rx ~= data.pointed.above.x - data.pointed.under.x then return end
|
|
local rz = recipe.normal.x * xz + recipe.normal.z * zz
|
|
if rz ~= data.pointed.above.z - data.pointed.under.z then return end
|
|
end
|
|
for _, v in pairs(recipe.nodes) do
|
|
if v ~= recipe.root and v.match then
|
|
local p = rel(v.x, v.y, v.z)
|
|
if not nodecore.match(p, v.match) then return end
|
|
end
|
|
end
|
|
if recipe.touchgroups then
|
|
local sum = {}
|
|
addgroups(sum, rel(1, 0, 0))
|
|
addgroups(sum, rel(-1, 0, 0))
|
|
addgroups(sum, rel(0, 1, 0))
|
|
addgroups(sum, rel(0, -1, 0))
|
|
addgroups(sum, rel(0, 0, 1))
|
|
addgroups(sum, rel(0, 0, -1))
|
|
for k, v in pairs(recipe.touchgroups) do
|
|
local w = sum[k] or 0
|
|
if v > 0 and w < v then return end
|
|
if v <= 0 and w > -v then return end
|
|
end
|
|
end
|
|
local mindur = recipe.duration or 0
|
|
if type(mindur) == "function" then mindur = mindur(recipe, pos, node, data) end
|
|
if recipe.toolgroups then
|
|
if not data.wield then return end
|
|
local dg = data.wield:get_tool_capabilities().groupcaps
|
|
local t
|
|
for gn, lv in pairs(recipe.toolgroups) do
|
|
local gt = dg[gn]
|
|
gt = gt and gt.times
|
|
gt = gt and gt[lv]
|
|
if gt and (not t or t > gt) then t = gt end
|
|
end
|
|
if not t then return end
|
|
mindur = mindur + t
|
|
end
|
|
mindur = mindur / recipe.rate_adjust
|
|
if mindur > 0 then
|
|
if not data.duration then return end
|
|
local dur = data.duration
|
|
if type(dur) == "function" then dur = dur(pos, data) end
|
|
if not dur or dur < mindur then
|
|
if data.inprogress then data.inprogress(pos, data) end
|
|
return 1
|
|
end
|
|
end
|
|
if data.before then data.before(pos, data) end
|
|
if recipe.before then recipe.before(pos, data) end
|
|
for _, v in ipairs(recipe.nodes) do
|
|
if v.replace then
|
|
local p = rel(v.x, v.y, v.z)
|
|
local r = v.replace
|
|
while type(r) == "function" do
|
|
r = r(p, v)
|
|
end
|
|
if r and type(r) == "string" then
|
|
r = {name = r}
|
|
end
|
|
if v.match.excess then
|
|
local s = nodecore.stack_get(p)
|
|
local x = s:get_count() - (v.match.count or 1)
|
|
if x > 0 then
|
|
s:set_count(x)
|
|
nodecore.item_eject(p, s, 0.001)
|
|
end
|
|
nodecore.stack_set(p, ItemStack(""))
|
|
end
|
|
if r then
|
|
local n = minetest.get_node(p)
|
|
r.param2 = n.param2
|
|
minetest.set_node(p, r)
|
|
nodecore.node_sound(p, "place")
|
|
nodecore.fallcheck(p)
|
|
end
|
|
end
|
|
end
|
|
if recipe.items then
|
|
for _, v in pairs(recipe.items) do
|
|
nodecore.item_eject(rel(v.x or 0, v.y or 0, v.z or 0),
|
|
v.name, v.scatter, v.count, v.velocity)
|
|
end
|
|
end
|
|
if recipe.consumewield then
|
|
nodecore.consume_wield(data.crafter, recipe.consumewield)
|
|
elseif recipe.toolgroups and recipe.toolwear and data.crafter then
|
|
nodecore.wear_wield(data.crafter, recipe.toolgroups, recipe.toolwear)
|
|
end
|
|
if recipe.after then recipe.after(pos, data) end
|
|
if data.after then data.after(pos, data) end
|
|
if nodecore.player_stat_add then
|
|
nodecore.player_stat_add(1, data.crafter, "craft", recipe.label)
|
|
end
|
|
if recipe.witness then
|
|
local lut = {}
|
|
for _, v in pairs(recipe.nodes) do
|
|
lut[minetest.pos_to_string(v)] = true
|
|
end
|
|
nodecore.witness(pos, recipe.label,
|
|
type(recipe.witness) == "number" and recipe.witness or nil,
|
|
function(p) return lut[minetest.pos_to_string(p)] end
|
|
)
|
|
end
|
|
minetest.log((data.crafter and data.crafter:get_player_name() or "unknown")
|
|
.. " completed recipe \"" .. recipe.label .. "\" at " ..
|
|
minetest.pos_to_string(pos) .. " upon " .. node.name)
|
|
return true
|
|
end
|
|
|
|
local function tryall(rc, pos, node, data)
|
|
local function go(xx, xz, zx, zz)
|
|
return craftcheck(rc, pos, node, data, xx, xz, zx, zz)
|
|
end
|
|
local r = go(1, 0, 0, 1)
|
|
if r then return r end
|
|
if not rc.norotate then
|
|
r = go(0, -1, 1, 0)
|
|
or go(-1, 0, 0, -1)
|
|
or go(0, 1, -1, 0)
|
|
if r then return r end
|
|
if not rc.nomirror then
|
|
r = go(-1, 0, 0, 1)
|
|
or go(0, 1, 1, 0)
|
|
or go(1, 0, 0, -1)
|
|
or go(0, -1, -1, 0)
|
|
end
|
|
end
|
|
return r
|
|
end
|
|
|
|
function nodecore.craft_check(pos, node, data)
|
|
data = data or {}
|
|
node.x = pos.x
|
|
node.y = pos.y
|
|
node.z = pos.z
|
|
data.pos = pos
|
|
data.node = node
|
|
for _, rc in ipairs(nodecore.craft_recipes) do
|
|
if data.action == rc.action
|
|
and nodecore.match(node, rc.root.match) then
|
|
data.recipe = rc
|
|
local r = tryall(rc, pos, node, data)
|
|
if r then return r == true end
|
|
end
|
|
end
|
|
end
|